computable_real/
real.rs

1use crate::{Approx, Primitive};
2
3use std::cmp::Ordering;
4use std::fmt::{self, Debug, Formatter};
5
6use num::bigint::Sign;
7use num::{BigInt, Integer, One, Signed, ToPrimitive, Zero};
8
9/// The main structure representing a real number.
10///
11/// It contains a private field which determines the function and the arguments,
12/// and the current best approximation, if any.
13///
14/// The core idea here is that we represent a real number as a function
15/// `f(n: i32) -> BigInt`, where `n` is the desired precision (typically
16/// negative). The function is constructed such that `|f(n)*2^n - x| < 2^n`.
17/// By using an increasingly negative `n`, we can approximate `x` to an
18/// arbitrary precision.
19///
20/// # Warning on Undefined Behavior
21///
22/// <div class="warning">
23/// Comparing two computable real numbers is inefficient, and indecidable in
24/// general. Because of this, we do not validate whether the arguments to the
25/// functions are valid. It is the user's responsibility to ensure that the
26/// arguments are in the function domain. Anything else will cause undefined
27/// behavior.
28/// </div>
29///
30/// The following things will cause undefined behavior, which may return an
31/// incorrect result, create an infinite loop, or panic:
32///
33/// - Division by zero
34/// - Calling [`Real::sqrt`] on a negative number
35/// - Calling [`Real::ln`] on a non-positive number
36/// - Calling [`Real::tan`] on a number where `cos` is zero
37/// - Calling [`Real::asin`] or [`Real::acos`] on a number outside [-1, 1]
38#[derive(Clone)]
39pub struct Real {
40    /// The primitive that represents the real number.
41    prim: Box<Primitive>,
42    /// The current best approximation of the real number.
43    pub approx: Option<Approx>,
44}
45
46impl Debug for Real {
47    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
48        write!(f, "{:?}", self.prim)
49    }
50}
51
52impl Real {
53    /// Creates a new real number from a primitive.
54    ///
55    /// Normally you would not use this directly, but rather use one of the
56    /// other associated functions like [`Real::int`] or [`Real::pi`].
57    pub fn new(prim: Primitive) -> Self {
58        Real {
59            prim: Box::new(prim),
60            approx: None,
61        }
62    }
63
64    /// Returns the most significant digit based on the current approximation,
65    /// or None if no approximation has been made.
66    ///
67    /// If msd is `n`, then `2^(n-1) < |x| < 2^(n+1)`.
68    pub(crate) fn known_msd(&self) -> Option<i32> {
69        let res = self.approx.as_ref()?;
70        let size = res.value.abs().bits() as i32;
71        Some(res.precision + size - 1)
72    }
73
74    /// Evaluates to the desired precision and returns the msd, or None if the
75    /// correct msd < precision.
76    pub(crate) fn msd(&mut self, precision: i32) -> Option<i32> {
77        if let Some(res) = &self.approx {
78            if res.value.abs() > BigInt::one() {
79                return self.known_msd();
80            }
81        }
82        let res = self.appr(precision - 1);
83        if res.value.abs() <= BigInt::one() {
84            // msd could still be arbitrarily far to the right
85            None
86        } else {
87            self.known_msd()
88        }
89    }
90
91    /// Iteratively lowers the precision until the msd is found, or the
92    /// provided minimum precision is reached.
93    pub(crate) fn iter_msd_n(&mut self, min_precision: i32) -> Option<i32> {
94        let mut curr = 0;
95        loop {
96            let msd = self.msd(curr);
97            if msd.is_some() {
98                return msd;
99            }
100            curr = (curr * 3) / 2 - 16;
101            if curr <= min_precision + 30 {
102                break;
103            }
104        }
105        self.msd(min_precision)
106    }
107
108    /// Iteratively lowers the precision until the msd is found. This will
109    /// cause an infinite loop if the value is zero.
110    pub(crate) fn iter_msd(&mut self) -> Option<i32> {
111        self.iter_msd_n(i32::MIN)
112    }
113
114    /// Generates an approximation of the real number.
115    ///
116    /// If we have already approximated the number with a sufficient precision,
117    /// we simply scale the approximation. Otherwise we call the underlying
118    /// approximate method.
119    ///
120    /// # Examples
121    /// ```
122    /// use computable_real::Real;
123    ///
124    /// let mut n = Real::from(42);
125    /// assert_eq!(n.appr(0).value, 42.into()); // 42*2^0 = 42
126    /// assert_eq!(n.appr(-1).value, 84.into()); // 84*2^-1 = 42
127    /// ```
128    pub fn appr(&mut self, precision: i32) -> Approx {
129        if let Some(res) = &self.approx {
130            if precision >= res.precision {
131                return res.scale_to(precision);
132            }
133        }
134        let res = self.prim.approximate(precision, self.clone());
135        self.approx = Some(res.clone());
136        res
137    }
138
139    /// Renders the number in `base` with `n` digits to the right of
140    /// decimal point.
141    ///
142    /// # Examples
143    /// ```
144    /// use computable_real::Real;
145    ///
146    /// let n = Real::from(42);
147    /// assert_eq!(n.render_base(0, 10), "42");
148    /// assert_eq!(n.render_base(2, 10), "42.00");
149    /// assert_eq!(n.render_base(4, 2), "101010.0000");
150    /// assert_eq!(n.render_base(0, 16), "2a");
151    ///
152    /// let pi = Real::pi();
153    /// assert_eq!(pi.render_base(10, 10), "3.1415926536");
154    /// assert_eq!(pi.render_base(10, 16), "3.243f6a8886");
155    /// assert_eq!(pi.render_base(10, 2), "11.0010010001");
156    /// ```
157    pub fn render_base(&self, n: u32, base: u32) -> String {
158        let scaled = match base {
159            16 => self.clone().shifted(n as i32 * 4),
160            _ => self.clone() * Real::int(BigInt::from(base).pow(n)),
161        }
162        .appr(0);
163
164        let value_str = scaled.value.abs().to_str_radix(base);
165
166        let padded_str = match value_str.len() as u32 {
167            len if len <= n => format!("{}{}", "0".repeat((n - len + 1) as usize), value_str),
168            _ => value_str,
169        };
170
171        let len = padded_str.len() as u32;
172        let (whole, frac) = padded_str.split_at((len - n) as usize);
173
174        let sign = if scaled.value.sign() == Sign::Minus {
175            "-"
176        } else {
177            ""
178        };
179        let dot = if n == 0 { "" } else { "." };
180        format!("{}{}{}{}", sign, whole, dot, frac)
181    }
182
183    /// Renders the number with `n` digits to the right of the decimal point.
184    ///
185    /// Equivalent to `render_base(n, 10)`.
186    ///
187    /// # Examples
188    /// ```
189    /// use computable_real::Real;
190    ///
191    /// let n = Real::from(42);
192    /// assert_eq!(n.render(0), "42");
193    /// assert_eq!(n.render(2), "42.00");
194    ///
195    /// let zero = Real::from(0);
196    /// assert_eq!(zero.render(0), "0");
197    /// assert_eq!(zero.render(2), "0.00");
198    ///
199    /// let minus_one = Real::from(-1);
200    /// assert_eq!(minus_one.render(0), "-1");
201    /// assert_eq!(minus_one.render(2), "-1.00");
202    /// ```
203    pub fn render(&self, n: u32) -> String {
204        self.render_base(n, 10)
205    }
206}
207
208/// Convenient methods and associated functions to create computable reals.
209impl Real {
210    /// Creates a computable real representing an integer.
211    ///
212    /// # Examples
213    /// ```
214    /// use computable_real::Real;
215    ///
216    /// let n = Real::int(42.into());
217    /// assert_eq!(n.render(0), "42");
218    /// ```
219    pub fn int(n: BigInt) -> Self {
220        Self::new(Primitive::Int(n))
221    }
222
223    /// Creates a computable real representing zero.
224    ///
225    /// Equivalent to `Real::int(BigInt::ZERO)`.
226    pub fn zero() -> Self {
227        Self::int(BigInt::ZERO)
228    }
229
230    /// Creates a computable real representing one.
231    ///
232    /// Equivalent to `Real::int(BigInt::one())`.
233    pub fn one() -> Self {
234        Self::int(BigInt::one())
235    }
236
237    /// Creates a computable real representing pi.
238    ///
239    /// This uses John Machin's formula from 1706:
240    /// `pi/4 = 4 * atan(1/5) - atan(1/239)`
241    ///
242    /// # Examples
243    /// ```
244    /// use computable_real::Real;
245    ///
246    /// let pi = Real::pi();
247    /// assert_eq!(pi.render(10), "3.1415926536");
248    /// ```
249    pub fn pi() -> Self {
250        let atan5 = Self::new(Primitive::Atan(BigInt::from(5)));
251        let atan239 = Self::new(Primitive::Atan(BigInt::from(239)));
252        let four_atan5 = Real::from(4) * atan5;
253        let diff = four_atan5 - atan239;
254        diff * Real::from(4)
255    }
256
257    /// Creates a computable real representing `self^2`.
258    ///
259    /// # Examples
260    /// ```
261    /// use computable_real::Real;
262    ///
263    /// assert_eq!(Real::from(42).squared().render(0), "1764");
264    /// assert_eq!(Real::from(-42).squared().render(0), "1764");
265    /// assert_eq!(Real::from(1).squared().render(0), "1");
266    /// ```
267    pub fn squared(self) -> Self {
268        Self::new(Primitive::Square(self))
269    }
270
271    /// Creates a computable real representing `a` if `self < 0`, and `b`
272    /// otherwise.
273    ///
274    /// # Examples
275    /// ```
276    /// use computable_real::Real;
277    ///
278    /// let n = Real::from(42);
279    /// let m = Real::from(-42);
280    /// assert_eq!(n.clone().select(n.clone(), m.clone()).render(0), "-42");
281    /// assert_eq!(m.clone().select(n.clone(), m.clone()).render(0), "42");
282    /// ```
283    pub fn select(self, a: Self, b: Self) -> Self {
284        Self::new(Primitive::Select(self, a, b))
285    }
286
287    /// Creates a computable real representing `exp(self)`.
288    ///
289    /// # Examples
290    /// ```
291    /// use computable_real::Real;
292    ///
293    /// let n = Real::one();
294    /// let e = n.exp();
295    /// assert_eq!(e.render(10), "2.7182818285");
296    /// ```
297    pub fn exp(mut self) -> Self {
298        let rough_appr = self.appr(-10).value;
299        let two = BigInt::from(2);
300        if rough_appr.abs() > two {
301            // If x >= 2*2^-10, we scale the argument into range
302            // exp(x) = exp(x/2)^2
303            self.shifted(-1).exp().squared()
304        } else {
305            Self::new(Primitive::Exp(self))
306        }
307    }
308
309    /// Creates a computable real representing `cos(self)`.
310    ///
311    /// # Examples
312    /// ```
313    /// use computable_real::Real;
314    ///
315    /// let cos_pi = Real::pi().cos();
316    /// assert_eq!(cos_pi.render(0), "-1");
317    ///
318    /// let cos_pi_half = Real::pi().shifted(-1).cos();
319    /// assert_eq!(cos_pi_half.render(0), "0");
320    ///
321    /// let cos_n3_pi = (Real::pi() * Real::from(-3)).cos();
322    /// assert_eq!(cos_n3_pi.render(0), "-1");
323    ///
324    /// let cos_pi_over_3 = (Real::pi() / Real::from(3)).cos();
325    /// assert_eq!(cos_pi_over_3.render(2), "0.50");
326    /// ```
327    pub fn cos(mut self) -> Self {
328        let half_pi_multiples = (self.clone() / Self::pi()).appr(-1).value;
329        let two = BigInt::from(2);
330
331        if half_pi_multiples.abs() >= two {
332            // If |arg| >= pi, we move the argument into range
333            let pi_multiples: BigInt = super::scale(half_pi_multiples.clone(), -1);
334            let adj = Self::pi() * Real::from(pi_multiples.clone());
335            if pi_multiples.is_even() {
336                (self - adj).cos()
337            } else {
338                -(self - adj).cos()
339            }
340        } else if self.appr(-1).value.abs() >= two {
341            // If 1 <= |arg| <= pi, use cos double angle formula:
342            // cos(x) = 2 * cos(x/2)^2  - 1
343            self.shifted(-1).cos().squared().shifted(1) - Self::one()
344        } else {
345            // If |arg| < 1
346            Self::new(Primitive::Cos(self))
347        }
348    }
349
350    /// Creates a computable real representing `sin(self)`.
351    ///
352    /// # Examples
353    /// ```
354    /// use computable_real::{Real, Comparator};
355    /// use std::cmp::Ordering;
356    ///
357    /// let sin_pi = Real::pi().sin();
358    /// assert_eq!(sin_pi.render(0), "0");
359    ///
360    /// let sin_pi_half = Real::pi().shifted(-1).sin();
361    /// assert_eq!(sin_pi_half.render(0), "1");
362    ///
363    /// let sin_n3_pi = (Real::pi() * Real::from(-3)).sin();
364    /// assert_eq!(sin_n3_pi.render(0), "0");
365    ///
366    /// // sin(pi/3) = sqrt(3)/2
367    /// let cmp = Comparator::new().min_prec(-10);
368    /// let mut sin_pi_over_3 = (Real::pi() / Real::from(3)).sin();
369    /// let mut sqrt_3_over_2 = Real::from(3).sqrt() / Real::from(2);
370    /// assert_eq!(cmp.cmp(&mut sin_pi_over_3, &mut sqrt_3_over_2), Ordering::Equal);
371    /// ```
372    pub fn sin(self) -> Self {
373        // sin(x) = cos(pi/2 - x)
374        (Self::pi().shifted(-1) - self).cos()
375    }
376
377    /// Creates a computable real representing `tan(self)`.
378    ///
379    /// # Examples
380    /// ```
381    /// use computable_real::Real;
382    ///
383    /// let tan_pi = Real::pi().tan();
384    /// assert_eq!(tan_pi.render(0), "0");
385    ///
386    /// let tan_n3_pi = (Real::pi() * Real::from(-3)).tan();
387    /// assert_eq!(tan_n3_pi.render(0), "0");
388    ///
389    /// let tan_pi_over_3 = (Real::pi() / Real::from(3)).tan();
390    /// assert_eq!(tan_pi_over_3.render(0), "2");
391    /// ```
392    pub fn tan(self) -> Self {
393        // tan(x) = sin(x) / cos(x)
394        self.clone().sin() / self.cos()
395    }
396
397    /// Creates a computable real representing `asin(self)`.
398    ///
399    /// # Examples
400    /// ```
401    /// use computable_real::{Real, Comparator};
402    /// use std::cmp::Ordering;
403    ///
404    /// let asin_zero = Real::from(0).asin();
405    /// assert_eq!(asin_zero.render(0), "0");
406    ///
407    /// let cmp = Comparator::new().min_prec(-10);
408    ///
409    /// let mut asin_one = Real::from(1).asin();
410    /// let mut half_pi = Real::pi().shifted(-1);
411    /// assert_eq!(cmp.cmp(&mut asin_one, &mut half_pi), Ordering::Equal);
412    ///
413    /// let n_one_sqrt_2 = Real::from(-1) / Real::from(2).sqrt();
414    /// let mut val = n_one_sqrt_2.asin();
415    /// let mut n_pi_over_4 = -Real::pi().shifted(-2);
416    /// assert_eq!(cmp.cmp(&mut val, &mut n_pi_over_4), Ordering::Equal);
417    /// ```
418    pub fn asin(mut self) -> Self {
419        let rough_appr = self.appr(-10).value;
420        // 750*2^-10 is slightly larger than sin(pi/4) = 1/sqrt(2)
421        if rough_appr > 750.into() {
422            // Use asin(x) = acos(sqrt(1 - x^2)), follows from sin^2 + cos^2 = 1
423            (Self::one() - self.squared()).sqrt().acos()
424        } else if rough_appr < (-750).into() {
425            -(-self.asin())
426        } else {
427            Self::new(Primitive::Asin(self))
428        }
429    }
430
431    /// Creates a computable real representing `acos(self)`.
432    ///
433    /// # Examples
434    /// ```
435    /// use computable_real::{Real, Comparator};
436    /// use std::cmp::Ordering;
437    ///
438    /// let cmp = Comparator::new().min_prec(-10);
439    ///
440    /// let mut acos_zero = Real::from(0).acos();
441    /// let mut half_pi = Real::pi().shifted(-1);
442    /// assert_eq!(cmp.cmp(&mut acos_zero, &mut half_pi), Ordering::Equal);
443    ///
444    /// let mut acos_one = Real::from(1).acos();
445    /// assert_eq!(cmp.cmp(&mut acos_one, &mut Real::from(0)), Ordering::Equal);
446    ///
447    /// let mut acos_half = Real::from(1).shifted(-1).acos();
448    /// let mut pi_over_3 = Real::pi() / Real::from(3);
449    /// assert_eq!(cmp.cmp(&mut acos_half, &mut pi_over_3), Ordering::Equal);
450    /// ```
451    pub fn acos(self) -> Self {
452        // acos(x) = pi/2 - asin(x)
453        Self::pi().shifted(-1) - self.asin()
454    }
455
456    /// Creates a computable real representing `atan(self)`.
457    ///
458    /// # Examples
459    /// ```
460    /// use computable_real::{Real, Comparator};
461    /// use std::cmp::Ordering;
462    ///
463    /// let atan_zero = Real::from(0).atan();
464    /// assert_eq!(atan_zero.render(0), "0");
465    ///
466    /// let cmp = Comparator::new().min_prec(-10);
467    ///
468    /// let mut atan_one = Real::from(1).atan();
469    /// let mut pi_over_4 = Real::pi().shifted(-2);
470    /// assert_eq!(cmp.cmp(&mut atan_one, &mut pi_over_4), Ordering::Equal);
471    ///
472    /// let n_one_sqrt_3 = Real::from(-1) / Real::from(3).sqrt();
473    /// let mut val = n_one_sqrt_3.atan();
474    /// let mut n_pi_over_6 = -Real::pi() / Real::from(6);
475    /// assert_eq!(cmp.cmp(&mut val, &mut n_pi_over_6), Ordering::Equal);
476    /// ```
477    pub fn atan(self) -> Self {
478        // sin(x)^2 = (tan(x)^2) / (1 + tan(x)^2)
479        let square = self.clone().squared();
480        let abs_sin_atan = (square.clone() / (Self::one() + square)).sqrt();
481        let sin_atan = self.select(-abs_sin_atan.clone(), abs_sin_atan);
482        sin_atan.asin()
483    }
484
485    fn simple_ln(self) -> Self {
486        Self::new(Primitive::Ln(self - Self::one()))
487    }
488
489    /// Creates a computable real representing `ln(self)`, the natural logarithm.
490    ///
491    /// # Examples
492    /// ```
493    /// use computable_real::Real;
494    ///
495    /// let ln1 = Real::from(1).ln();
496    /// assert_eq!(ln1.render(0), "0");
497    ///
498    /// let e = Real::from(1).exp();
499    /// let ln_e = e.ln();
500    /// assert_eq!(ln_e.render(0), "1");
501    /// ```
502    pub fn ln(mut self) -> Self {
503        let rough_appr = self.appr(-4).value;
504        if rough_appr <= 8.into() {
505            // If x <= 8*2^-4 = 0.5, we use ln(x) = -ln(1/x)
506            -((Self::one() / self).ln())
507        } else if rough_appr >= 24.into() {
508            // If x >= 24*2^-4 = 1.5:
509            if rough_appr <= 64.into() {
510                // If 1.5 <= x <= 64*2^-4 = 4, we use ln(x) = 4*ln(sqrt(sqrt(x)))
511                self.sqrt().sqrt().ln().shifted(2)
512            } else {
513                // If x > 4:
514                let ln2_1 = Real::from(7) * (Real::from(10) / Real::from(9)).simple_ln();
515                let ln2_2 = Real::from(2) * (Real::from(25) / Real::from(24)).simple_ln();
516                let ln2_3 = Real::from(3) * (Real::from(81) / Real::from(80)).simple_ln();
517                // 7*ln(10/9) - 2*ln(25/24) + 3*ln(81/80) = ln(2)
518                let ln2 = ln2_1 - ln2_2 + ln2_3;
519                let extra_bits = rough_appr.bits() as i32 - 3;
520                // ln(x) = ln(x/2^extra_bits) + extra_bits*ln(2)
521                self.shifted(-extra_bits).ln() + Real::from(extra_bits) * ln2
522            }
523        } else {
524            // If 0.5 < x < 1.5, we can directly use the primitive
525            self.simple_ln()
526        }
527    }
528
529    /// Creates a computable real representing `sqrt(self)`.
530    ///
531    /// # Examples
532    /// ```
533    /// use computable_real::Real;
534    ///
535    /// let sqrt_2 = Real::from(2).sqrt();
536    /// assert_eq!(sqrt_2.render(10), "1.4142135624");
537    ///
538    /// let sqrt_1 = Real::from(1).sqrt();
539    /// assert_eq!(sqrt_1.render(0), "1");
540    ///
541    /// let sqrt_0 = Real::from(0).sqrt();
542    /// assert_eq!(sqrt_0.render(0), "0");
543    ///
544    /// let sqrt_quarter = Real::from(1).shifted(-2).sqrt();
545    /// assert_eq!(sqrt_quarter.render(3), "0.500");
546    /// ```
547    pub fn sqrt(self) -> Self {
548        Self::new(Primitive::Sqrt(self))
549    }
550
551    /// Creates a computable real representing `self * 2^n`.
552    ///
553    /// # Examples
554    /// ```
555    /// use computable_real::Real;
556    ///
557    /// assert_eq!(Real::from(42).shifted(0).render(0), "42");
558    /// assert_eq!(Real::from(42).shifted(2).render(0), "168");
559    /// assert_eq!(Real::from(42).shifted(-2).render(3), "10.500");
560    /// assert_eq!(Real::from(42).shifted(-2).shifted(2).render(0), "42");
561    /// ```
562    pub fn shifted(self, n: i32) -> Self {
563        Self::new(Primitive::Shift(self, n))
564    }
565
566    /// Creates a computable real representing `1/self`.
567    ///
568    /// # Examples
569    /// ```
570    /// use computable_real::Real;
571    ///
572    /// assert_eq!(Real::from(42).inv().render(10), "0.0238095238");
573    /// assert_eq!(Real::from(1).inv().render(0), "1");
574    /// assert_eq!(Real::from(-1).inv().render(0), "-1");
575    /// assert_eq!(Real::from(42).inv().inv().render(0), "42");
576    /// ```
577    pub fn inv(self) -> Self {
578        Self::new(Primitive::Inv(self))
579    }
580}
581
582/// Utility struct to compare real numbers.
583///
584/// One limitiation of computable real numbers is that, in general whether two
585/// numbers are equal is undecidable. We could evaluate them to incraesingly
586/// high precision until they diverge, but if they are in fact equal, this
587/// would never terminate.
588///
589/// Given this, we provide the [Comparator] struct to compare real numbers and
590/// get the sign of a real number. You will have to provide some kind of
591/// tolerance level for the comparison.
592///
593/// Three different precision levels can be configured, and they are all
594/// typically negative:
595/// - [`Comparator::rel`] sets the relative precision level
596/// - [`Comparator::abs`] sets the absolute precision level
597/// - [`Comparator::min_prec`] sets the minimum precision level
598///
599/// The relative level is added on top of `max(msd(a), msd(b))` to determine the
600/// precision we evaluate the numbers to to perform the comparison. Here `msd`
601/// is defined as the binary position of the most significant digit, such that
602/// `2^(msd-1) < |x| < 2^(msd+1)`. Note that the relative level is only used
603/// if the absolute level is set.
604///
605/// If no relative level is set, the numbers will be evaluated to the absolute
606/// level for comparison. If the relative level is set, the precision will be
607/// taken as the maximum between the relative and absolute levels.
608///
609/// The minimum precision level sets a bound of the evaluation precision. We
610/// will never evaluate the numbers to a precision beyond this. When no
611/// absolute level is set, we will iteratively evaluate the numbers until they
612/// diverge, or until the minimum precision level is reached.
613///
614/// # Examples
615///
616/// ```
617/// use computable_real::{Comparator, Real};
618/// use std::cmp::Ordering;
619///
620/// let mut one = Real::from(1);
621/// let mut pi = Real::pi();
622///
623/// let cmp = Comparator::new();
624/// assert_eq!(cmp.cmp(&mut one, &mut pi), Ordering::Less);
625///
626/// // A comparator that will only evaluate to 2^-10 precision
627/// let lazy_cmp = Comparator::new().abs(-10);
628/// let mut smol = Real::from(1).shifted(-100);
629/// // It cannot tell smol from 0
630/// assert_eq!(lazy_cmp.signum(&mut smol), 0);
631/// let mut pi_smol = pi.clone() + smol.clone();
632/// // It cannot tell pi + smol from pi
633/// assert_eq!(lazy_cmp.cmp(&mut pi_smol, &mut pi), Ordering::Equal);
634///
635/// // The default comparator can correctly compare
636/// assert_eq!(cmp.signum(&mut smol), 1);
637/// assert_eq!(cmp.cmp(&mut pi_smol, &mut pi), Ordering::Greater);
638/// ```
639pub struct Comparator {
640    rel: Option<i32>,
641    abs: Option<i32>,
642    min: i32,
643}
644
645impl Default for Comparator {
646    /// Equivalent to [`Comparator::new`].
647    fn default() -> Self {
648        Self::new()
649    }
650}
651
652impl Comparator {
653    /// Returns a new comparator with no relative and absolute precision levels,
654    /// and a minimum precision level of `i32::MIN`.
655    ///
656    /// <div class="warning">
657    /// You can use the returned comparator as is, but if you compare two equal
658    /// numbers or call [`Comparator::signum`] on zero, it can cause an
659    /// infinite loop.
660    ///
661    /// When two numbers may be equal, you should set at least the absolute
662    /// precision or the minimum precision level.
663    /// </div>
664    pub fn new() -> Self {
665        Self {
666            rel: None,
667            abs: None,
668            min: i32::MIN,
669        }
670    }
671
672    /// Sets the relative precision level.
673    pub fn rel(mut self, value: i32) -> Self {
674        self.rel = Some(value);
675        self
676    }
677
678    /// Sets the absolute precision level.
679    pub fn abs(mut self, value: i32) -> Self {
680        self.abs = Some(value);
681        self
682    }
683
684    /// Sets the minimum precision level.
685    pub fn min_prec(mut self, value: i32) -> Self {
686        self.min = value;
687        self
688    }
689
690    /// Compares two real numbers.
691    ///
692    /// See examples in [`Comparator#examples`].
693    pub fn cmp(&self, a: &mut Real, b: &mut Real) -> Ordering {
694        if let Some(abs) = self.abs {
695            let tol = if let Some(rel) = self.rel {
696                let msd = match (a.iter_msd_n(abs), b.iter_msd_n(abs)) {
697                    (Some(msd1), Some(msd2)) => msd1.max(msd2),
698                    (Some(msd1), None) => msd1,
699                    (None, Some(msd2)) => msd2,
700                    (None, None) => return Ordering::Equal,
701                };
702                abs.max(msd + rel)
703            } else {
704                abs
705            };
706
707            let prec = self.min.max(tol - 1);
708            let a = a.appr(prec).value;
709            let b = b.appr(prec).value;
710            return a.cmp(&b);
711        }
712
713        let mut prec = -16;
714        let mut cmp = Comparator::new().min_prec(self.min);
715        loop {
716            cmp.abs = Some(prec);
717            let res = cmp.cmp(a, b);
718            prec *= 2;
719            if res != Ordering::Equal || prec <= self.min {
720                return res;
721            }
722        }
723    }
724
725    /// Returns the sign of a real number.
726    ///
727    /// See examples in [`Comparator#examples`].
728    pub fn signum(&self, n: &mut Real) -> i32 {
729        if let Some(res) = &n.approx {
730            if !res.value.is_zero() {
731                return res.value.signum().to_i32().unwrap();
732            }
733        }
734
735        match self.cmp(n, &mut Real::from(0)) {
736            Ordering::Less => -1,
737            Ordering::Equal => 0,
738            Ordering::Greater => 1,
739        }
740    }
741}