computable_real/
traits.rs

1use crate::{Primitive, Real};
2
3use std::convert::From;
4use std::ops::{Add, Div, Mul, Neg, Sub};
5use std::str::FromStr;
6
7use num::bigint::ParseBigIntError;
8use num::{BigInt, BigRational, Num, ToPrimitive};
9
10impl Add for Real {
11    type Output = Self;
12
13    /// Adds two real numbers by consuming them and returning a new real number.
14    ///
15    /// # Examples
16    /// ```
17    /// use computable_real::Real;
18    ///
19    /// assert_eq!((Real::from(1) + Real::from(2)).render(0), "3");
20    /// assert_eq!((Real::from(1) + Real::from(-1)).render(0), "0");
21    /// assert_eq!((Real::pi() + Real::from(1).exp()).render(5), "5.85987");
22    /// ```
23    fn add(self, rhs: Self) -> Self {
24        Self::new(Primitive::Add(self, rhs))
25    }
26}
27
28impl Neg for Real {
29    type Output = Self;
30
31    /// Negates a real number by consuming it and returning a new real number.
32    fn neg(self) -> Self {
33        Self::new(Primitive::Neg(self))
34    }
35}
36
37impl Sub for Real {
38    type Output = Self;
39
40    /// Subtracts two real numbers by consuming them and returning a new real
41    /// number.
42    ///
43    /// # Examples
44    /// ```
45    /// use computable_real::Real;
46    ///
47    /// assert_eq!((Real::from(1) - Real::from(2)).render(0), "-1");
48    /// assert_eq!((Real::from(1) - Real::from(-1)).render(0), "2");
49    /// assert_eq!((Real::from(1) - Real::from(1)).render(0), "0");
50    /// assert_eq!((Real::pi() - Real::from(1).exp()).render(5), "0.42331");
51    /// ```
52    fn sub(self, rhs: Self) -> Self {
53        self + -rhs
54    }
55}
56
57impl Mul for Real {
58    type Output = Self;
59
60    /// Multiplies two real numbers by consuming them and returning a new real
61    /// number.
62    ///
63    /// # Examples
64    /// ```
65    /// use computable_real::Real;
66    ///
67    /// assert_eq!((Real::from(1) * Real::from(2)).render(0), "2");
68    /// assert_eq!((Real::from(1) * Real::from(-1)).render(0), "-1");
69    /// assert_eq!((Real::pi() * Real::from(-1)).render(5), "-3.14159");
70    /// assert_eq!((Real::pi() * Real::from(0)).render(5), "0.00000");
71    /// ```
72    fn mul(self, rhs: Self) -> Self {
73        Self::new(Primitive::Mul(self, rhs))
74    }
75}
76
77impl Div for Real {
78    type Output = Self;
79
80    /// Divides two real numbers by consuming them and returning a new real
81    /// number.
82    ///
83    /// # Examples
84    /// ```
85    /// use computable_real::Real;
86    ///
87    /// assert_eq!((Real::from(1) / Real::from(2)).render(5), "0.50000");
88    /// assert_eq!((Real::from(1) / Real::from(-1)).render(5), "-1.00000");
89    /// assert_eq!((Real::pi() / Real::from(1).exp()).render(5), "1.15573");
90    /// ```
91    fn div(self, rhs: Self) -> Self {
92        self.mul(Real::new(Primitive::Inv(rhs)))
93    }
94}
95
96impl From<BigInt> for Real {
97    /// Converts a `BigInt` into a real number.
98    ///
99    /// # Examples
100    /// ```
101    /// use computable_real::Real;
102    /// use num::BigInt;
103    ///
104    /// let n: BigInt = "-123456789012345678901234567890".parse().unwrap();
105    /// let r: Real = n.into();
106    /// assert_eq!(r.render(0), "-123456789012345678901234567890");
107    /// ```
108    fn from(value: BigInt) -> Self {
109        Real::int(value)
110    }
111}
112
113impl From<i32> for Real {
114    /// Converts an `i32` into a real number.
115    ///
116    /// Equivalent to `Real::int(BigInt::from(value))`.
117    fn from(value: i32) -> Self {
118        Real::int(value.into())
119    }
120}
121
122impl From<BigRational> for Real {
123    /// Converts a `BigRational` into a real number.
124    ///
125    /// # Examples
126    /// ```
127    /// use computable_real::Real;
128    /// use num::{BigInt, BigRational};
129    ///
130    /// let a = BigRational::new(BigInt::from(1), BigInt::from(2));
131    /// assert_eq!(Real::from(a).render(5), "0.50000");
132    ///
133    /// let b = BigRational::new(BigInt::from(-1), BigInt::from(3));
134    /// assert_eq!(Real::from(b).render(5), "-0.33333");
135    /// ```
136    fn from(value: BigRational) -> Self {
137        let (num, denom) = value.into_raw();
138        Real::int(num) / Real::int(denom)
139    }
140}
141
142impl From<f64> for Real {
143    /// Converts an `f64` into a real number.
144    ///
145    /// Note that due to the inherent imprecision of floating point numbers,
146    /// the conversion may not be exact.
147    ///
148    /// # Examples
149    /// ```
150    /// use computable_real::Real;
151    ///
152    /// let r: Real = 3.14.into();
153    /// assert_eq!(r.render(2), "3.14");
154    /// assert_eq!(r.render(20), "3.14000000000000012434");
155    ///
156    /// let s: Real = (-0.0003).into();
157    /// assert_eq!(s.render(5), "-0.00030");
158    /// ```
159    fn from(value: f64) -> Self {
160        let bits = value.abs().to_bits() as i64;
161        let mut mantissa = bits & ((1 << 52) - 1);
162        let biased_exponent = (bits >> 52) as i32;
163        // Instead of 1023, we adjust by an additional 52 to compensate for
164        //  the fact that our mantissa is an integer.
165        let exponent = biased_exponent - 1075;
166        match biased_exponent {
167            0 => {
168                mantissa <<= 1;
169            }
170            _ => {
171                mantissa += 1 << 52;
172            }
173        }
174        let res = Real::int(mantissa.into()).shifted(exponent);
175        if value < 0.0 {
176            -res
177        } else {
178            res
179        }
180    }
181}
182
183impl From<Real> for f64 {
184    /// Converts a real number into an `f64`.
185    ///
186    /// # Examples
187    /// ```
188    /// use computable_real::Real;
189    ///
190    /// let pi = Real::pi();
191    /// let f: f64 = pi.into();
192    /// assert_eq!(f, std::f64::consts::PI);
193    /// ```
194    fn from(mut value: Real) -> f64 {
195        // Slightly beyond -1023 - 52 = -1075
196        let msd = value.iter_msd_n(-1080);
197        if msd.is_none() {
198            // The number is close enoug to zero so we just return zero
199            return 0.0;
200        }
201        let prec = msd.unwrap() - 60;
202        let value = value.appr(prec).value.to_f64().unwrap();
203        let may_underflow = prec < -1000;
204        let mut bits = value.to_bits() as i64;
205        let exp_adj = (if may_underflow { prec + 96 } else { prec }) as i64;
206        let exp = (bits >> 52) & 0x7ff;
207
208        if exp + exp_adj >= 0x7ff {
209            return if value.is_sign_positive() {
210                f64::INFINITY
211            } else {
212                f64::NEG_INFINITY
213            };
214        }
215
216        bits += exp_adj << 52;
217        let res = f64::from_bits(bits as u64);
218
219        if may_underflow {
220            // Compensate for the extra 96 in exponent
221            // Dividing by 2^48 twice instead of 2^96 for gradual underflow
222            let two_48 = (1_u64 << 48) as f64;
223            res / two_48 / two_48
224        } else {
225            res
226        }
227    }
228}
229
230impl From<Real> for BigInt {
231    /// Converts a real number into a `BigInt`.
232    ///
233    /// It is guaranteed that the difference is less than 1.
234    ///
235    /// # Examples
236    /// ```
237    /// use computable_real::Real;
238    /// use num::BigInt;
239    ///
240    /// let a = Real::from(-42);
241    /// assert_eq!(BigInt::from(a).to_string(), "-42");
242    ///
243    /// let b = Real::from(0.999);
244    /// assert!(BigInt::from(b) <= 1.into());
245    /// ```
246    fn from(mut value: Real) -> BigInt {
247        value.appr(0).value
248    }
249}
250
251impl FromStr for Real {
252    type Err = ParseBigIntError;
253
254    /// Parses a decimal string into a real number.
255    ///
256    /// # Examples
257    /// ```
258    /// use computable_real::Real;
259    /// use std::str::FromStr;
260    ///
261    /// let a: Real = "3.14".parse().unwrap();
262    /// assert_eq!(a.render(2), "3.14");
263    ///
264    /// let b: Real = "-0.0000000000000000042".parse().unwrap();
265    /// assert_eq!(b.render(20), "-0.00000000000000000420");
266    ///
267    /// let c: Real = "42".parse().unwrap();
268    /// assert_eq!(c.render(0), "42");
269    /// ```
270    fn from_str(str: &str) -> Result<Self, Self::Err> {
271        let len = str.trim().len();
272        let frac_len = match str.find('.') {
273            Some(i) => len - i - 1,
274            None => 0,
275        };
276        let removed_dot = str.replace(".", "");
277        let int = BigInt::from_str_radix(&removed_dot, 10)?;
278        let div = BigInt::from(10).pow(frac_len as u32);
279        Ok(Real::int(int) / Real::int(div))
280    }
281}