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}