gosper/terms.rs
1//! Wrapper newtypes for marking continued fraction terms
2//!
3//! # Example
4//!
5//! ```rust
6//! use gosper::{ContinuedFraction, terms};
7//!
8//! let regular = terms::Regular::from([1, 2, 3]);
9//! let cf = ContinuedFraction::new(regular);
10//!
11//! assert_eq!(format!("{:#}", cf), "[1;2,3]");
12//! ```
13use num::BigInt;
14
15use crate::{float, homographic, iter, rational, ContinuedFraction};
16
17/// Wrapper newtype for an iterator of regular continued fraction terms
18pub struct Regular<I: Iterator<Item = BigInt>>(pub I);
19
20/// Wrapper newtype for an iterator of generalized continued fraction terms
21pub struct Rational<I: Iterator<Item = rational::Rational>>(pub I);
22
23/// Wrapper newtype for an iterator of decimal terms
24pub struct Decimal<I: Iterator<Item = BigInt>>(pub I);
25
26/// Convert a continued fraction reference to regular terms
27///
28/// # Example
29///
30/// ```rust
31/// # use gosper::*;
32/// let a = ContinuedFraction::from(consts::Pi);
33///
34/// // The turbofish below is necessary to disambiguate the `From` implementation.
35/// let regular = terms::Regular::<iter::MemoIter<_>>::from(&a);
36/// let b = ContinuedFraction::from(regular);
37///
38/// // Unless you actually need `terms::Regular`, in practice it's cleaner to `Clone`.
39/// let c = a.clone();
40///
41/// assert_eq!(format!("{:.2} {:.2} {:.2}", &a, &b, &c), "3.14 3.14 3.14");
42/// ```
43impl<I> From<&ContinuedFraction<I>> for Regular<iter::MemoIter<I>>
44where
45 I: Iterator<Item = BigInt>,
46{
47 fn from(value: &ContinuedFraction<I>) -> Self {
48 Self(value.iter())
49 }
50}
51
52/// Convert from iterables of integers
53///
54/// This implementation is most generic for regular continued fractions. It
55/// supports anything that can turn into an [`Iterator`] of any type of item
56/// that can be turned into a [`BigInt`].
57///
58/// # Example
59///
60/// ```rust
61/// # use gosper::*;
62///
63/// ContinuedFraction::from(vec![1, 2, 3, 4].into_iter());
64/// ```
65impl<I> From<I> for Regular<iter::ToBigInts<I::IntoIter>>
66where
67 I: IntoIterator,
68 BigInt: From<I::Item>,
69{
70 fn from(value: I) -> Self {
71 Self(iter::ToBigInts(value.into_iter()))
72 }
73}
74
75/// Convert an integer
76///
77/// # Example
78///
79/// ```rust
80/// # use gosper::*;
81/// let cf = ContinuedFraction::from(1_000);
82/// assert_eq!(cf.to_f64(), 1000.0);
83/// ```
84impl<I> From<I> for Regular<iter::Once<BigInt>>
85where
86 BigInt: From<I>,
87{
88 fn from(value: I) -> Self {
89 Self(iter::Once::from(BigInt::from(value)))
90 }
91}
92
93/// Convert a rational `num / den` from the tuple of `(num, den)` integers
94///
95/// # Example
96///
97/// ```rust
98/// # use gosper::*;
99/// let cf = ContinuedFraction::from((22, 7));
100/// assert_eq!(cf.to_f64(), 3.1428571428571423);
101/// ```
102impl<R> From<R> for Regular<rational::Solver>
103where
104 rational::Solver: From<R>,
105{
106 fn from(value: R) -> Self {
107 Self(rational::Solver::from(value))
108 }
109}
110
111/// Lossily convert a 64-bit float using the lentz algorithm
112///
113/// # Example
114///
115/// ```rust
116/// # use gosper::*;
117/// let cf = ContinuedFraction::from(3.14);
118/// assert_eq!(cf.to_f64(), 3.1399999999999992);
119/// ```
120impl<T> From<T> for Regular<float::Solver>
121where
122 float::Solver: From<T>,
123{
124 fn from(value: T) -> Self {
125 Self(float::Solver::from(value))
126 }
127}
128
129impl<I> From<Rational<I>> for Regular<homographic::GeneralizedSolver<I>>
130where
131 I: Iterator<Item = rational::Rational>,
132{
133 fn from(value: Rational<I>) -> Self {
134 let Rational(iter) = value;
135 Self(homographic::Solver::identity(
136 homographic::input::Generalized(iter.peekable()),
137 homographic::output::Regular {},
138 ))
139 }
140}
141
142// impl<I, J> From<I> for Decimal<J>
143// where
144// J: Iterator<Item = BigInt>,
145// terms::Regular<J>: From<I>,
146// {
147
148impl<I, J> From<I> for Decimal<homographic::DecimalSolver<J>>
149where
150 J: Iterator<Item = BigInt>,
151 Regular<J>: From<I>,
152{
153 fn from(value: I) -> Self {
154 let Regular(iter) = Regular::from(value);
155 Self(homographic::Solver::identity(
156 homographic::input::Regular(iter.peekable()),
157 homographic::output::Decimal {},
158 ))
159 }
160}