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}