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}