computable_real/
traits.rs

1use super::{Primitive, Real};
2use num::bigint::ParseBigIntError;
3use num::{BigInt, BigRational, Num, One, Signed, ToPrimitive, Zero};
4use std::cmp::Ordering;
5use std::convert::{From, Into};
6use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
7use std::str::FromStr;
8
9impl PartialEq for Real {
10    fn eq(&self, other: &Self) -> bool {
11        self.cmp(other) == Ordering::Equal
12    }
13}
14
15impl Eq for Real {}
16
17impl PartialOrd for Real {
18    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
19        Some(self.cmp(other))
20    }
21}
22
23impl Ord for Real {
24    fn cmp(&self, other: &Self) -> Ordering {
25        self.cmp_until(other, super::CMP_MIN_PRECISION)
26    }
27}
28
29impl Add for Real {
30    type Output = Self;
31
32    fn add(self, rhs: Self) -> Self {
33        Self::new(Primitive::Add(self, rhs))
34    }
35}
36
37impl Neg for Real {
38    type Output = Self;
39
40    fn neg(self) -> Self {
41        Self::new(Primitive::Neg(self))
42    }
43}
44
45impl Sub for Real {
46    type Output = Self;
47
48    fn sub(self, rhs: Self) -> Self {
49        self + -rhs
50    }
51}
52
53impl Mul for Real {
54    type Output = Self;
55
56    fn mul(self, rhs: Self) -> Self {
57        Self::new(Primitive::Mul(self, rhs))
58    }
59}
60
61impl Div for Real {
62    type Output = Self;
63
64    fn div(self, rhs: Self) -> Self {
65        self * Real::new(Primitive::Inv(rhs))
66    }
67}
68
69impl Rem for Real {
70    type Output = Self;
71
72    fn rem(self, rhs: Self) -> Self {
73        let lhs: BigInt = self.into();
74        let rhs: BigInt = rhs.into();
75        Real::int(lhs % rhs)
76    }
77}
78
79impl From<BigInt> for Real {
80    fn from(value: BigInt) -> Self {
81        Real::int(value)
82    }
83}
84
85impl From<i32> for Real {
86    fn from(value: i32) -> Self {
87        Real::int(value.into())
88    }
89}
90
91impl From<BigRational> for Real {
92    fn from(value: BigRational) -> Self {
93        Real::int(value.numer().clone()) / Real::int(value.denom().clone())
94    }
95}
96
97impl From<f64> for Real {
98    fn from(value: f64) -> Self {
99        let bits = value.abs().to_bits() as i64;
100        let mut mantissa = bits & ((1 << 52) - 1);
101        let biased_exponent = (bits >> 52) as i32;
102        // Instead of 1023, we adjust by an additional 52 to compensate for
103        //  the fact that our mantissa is an integer.
104        let exponent = biased_exponent - 1075;
105        match biased_exponent {
106            0 => {
107                mantissa <<= 1;
108            }
109            _ => {
110                mantissa += 1 << 52;
111            }
112        }
113        let res = Real::int(mantissa.into()).shifted(exponent);
114        if value < 0.0 {
115            -res
116        } else {
117            res
118        }
119    }
120}
121
122impl Into<f64> for Real {
123    fn into(mut self) -> f64 {
124        // Slightly beyond -1023 - 52 = -1075
125        let msd = self.iter_msd_n(-1080);
126        if msd.is_none() {
127            // The number is close enoug to zero so we just return zero
128            return 0.0;
129        }
130        let prec = msd.unwrap() - 60;
131        let value = self.appr(prec).value.to_f64().unwrap();
132        let may_underflow = prec < -1000;
133        let mut bits = value.to_bits() as i64;
134        let exp_adj = (if may_underflow { prec + 96 } else { prec }) as i64;
135        let exp = (bits >> 52) & 0x7ff;
136
137        if exp + exp_adj >= 0x7ff {
138            return if value.is_sign_positive() {
139                f64::INFINITY
140            } else {
141                f64::NEG_INFINITY
142            };
143        }
144
145        bits += exp_adj << 52;
146        let res = f64::from_bits(bits as u64);
147
148        if may_underflow {
149            // Compensate for the extra 96 in exponent
150            // Dividing by 2^48 twice instead of 2^96 for gradual underflow
151            let two_48 = (1_u64 << 48) as f64;
152            res / two_48 / two_48
153        } else {
154            res
155        }
156    }
157}
158
159impl Into<BigInt> for Real {
160    fn into(mut self) -> BigInt {
161        self.appr(0).value
162    }
163}
164
165impl One for Real {
166    fn one() -> Self {
167        1.into()
168    }
169}
170
171impl Zero for Real {
172    fn zero() -> Self {
173        0.into()
174    }
175
176    fn is_zero(&self) -> bool {
177        self == &Real::zero()
178    }
179}
180
181impl Num for Real {
182    type FromStrRadixErr = ParseBigIntError;
183
184    fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
185        let len = str.trim().len();
186        let frac_len = match str.find('.') {
187            Some(i) => len - i - 1,
188            None => 0,
189        };
190        let removed_dot = str.replace(".", "");
191        let int = BigInt::from_str_radix(&removed_dot, radix)?;
192        let div = BigInt::from(radix).pow(frac_len as u32);
193        Ok(Real::int(int) / Real::int(div))
194    }
195}
196
197impl FromStr for Real {
198    type Err = ParseBigIntError;
199
200    fn from_str(str: &str) -> Result<Self, Self::Err> {
201        Real::from_str_radix(str, 10)
202    }
203}
204
205impl Signed for Real {
206    fn abs(&self) -> Self {
207        self.clone() * self.signum()
208    }
209
210    fn abs_sub(&self, other: &Self) -> Self {
211        if self < other {
212            Real::zero()
213        } else {
214            self.clone() - other.clone()
215        }
216    }
217
218    fn signum(&self) -> Self {
219        let mut a = -16;
220        loop {
221            let sign = self.signum_a(a);
222            if sign != 0 || a < super::CMP_MIN_PRECISION {
223                return sign.into();
224            }
225            a *= 2;
226        }
227    }
228
229    fn is_positive(&self) -> bool {
230        self > &Real::zero()
231    }
232
233    fn is_negative(&self) -> bool {
234        self < &Real::zero()
235    }
236}