1use crate::algebraic::{negative_root, Algebraic};
31use crate::interval::{ceil_div, floor_div, one, Dyadic, Iv};
32use crate::numeric::{rational_from_f64_exact, BigInt, Rational};
33use crate::ode::{Field, FlowError};
34use std::cmp::Ordering;
35use std::fmt;
36use std::sync::{Arc, Mutex, OnceLock};
37
38#[derive(Clone, Debug, PartialEq, Eq)]
42pub enum RealError {
43 Inseparable { what: String, bits: u32 },
45 Domain(String),
47}
48
49impl fmt::Display for RealError {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 RealError::Inseparable { what, bits } => write!(
53 f,
54 "cannot separate {what} within 2^-{bits}; they may be equal"
55 ),
56 RealError::Domain(why) => write!(f, "{why}"),
57 }
58 }
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63pub enum Closeness {
64 Less,
65 Greater,
66 Close,
67}
68
69fn atan_recip_scaled(n: i64, w: i64) -> (BigInt, BigInt) {
73 let nb = BigInt::from_i64(n);
74 let n2 = nb.mul(&nb);
75 let mut power = one().shl_bits(w as u64).div_rem(&nb).expect("n > 0").0;
76 let mut sum = BigInt::zero();
77 let mut k = 0i64;
78 while !power.is_zero() {
79 let term = power.div_rem(&BigInt::from_i64(2 * k + 1)).expect("odd").0;
80 sum = if k % 2 == 0 { sum.add(&term) } else { sum.sub(&term) };
81 power = power.div_rem(&n2).expect("n² > 0").0;
82 k += 1;
83 }
84 let err = BigInt::from_i64(3 * k + 3);
85 (sum.sub(&err), sum.add(&err))
86}
87
88fn pi_cache() -> &'static Mutex<Option<(i64, BigInt, BigInt)>> {
89 static CACHE: OnceLock<Mutex<Option<(i64, BigInt, BigInt)>>> = OnceLock::new();
90 CACHE.get_or_init(|| Mutex::new(None))
91}
92
93fn pi_iv(p: i64) -> Iv {
95 let p = p.max(8);
96 {
97 let cache = pi_cache().lock().expect("the π cache is never poisoned");
98 if let Some((w, lo, hi)) = cache.as_ref() {
99 if *w >= p {
100 let iv = Iv {
101 lo: Dyadic::new(lo.clone(), -w),
102 hi: Dyadic::new(hi.clone(), -w),
103 };
104 return iv.round_out(p);
105 }
106 }
107 }
108 let w = p + 24;
109 let (a_lo, a_hi) = atan_recip_scaled(5, w);
110 let (b_lo, b_hi) = atan_recip_scaled(239, w);
111 let sixteen = BigInt::from_i64(16);
112 let four = BigInt::from_i64(4);
113 let lo = sixteen.mul(&a_lo).sub(&four.mul(&b_hi));
114 let hi = sixteen.mul(&a_hi).sub(&four.mul(&b_lo));
115 *pi_cache().lock().expect("the π cache is never poisoned") = Some((w, lo.clone(), hi.clone()));
116 Iv {
117 lo: Dyadic::new(lo, -w),
118 hi: Dyadic::new(hi, -w),
119 }
120 .round_out(p)
121}
122
123fn atanh_scaled(z_num: &BigInt, z_den: &BigInt, w: i64) -> (BigInt, BigInt) {
126 let z2_num = z_num.mul(z_num);
127 let z2_den = z_den.mul(z_den);
128 let mut power = floor_div(&z_num.shl_bits(w as u64), z_den);
129 let mut sum = BigInt::zero();
130 let mut k = 0i64;
131 while !power.is_zero() {
132 sum = sum.add(&power.div_rem(&BigInt::from_i64(2 * k + 1)).expect("odd").0);
133 power = floor_div(&power.mul(&z2_num), &z2_den);
134 k += 1;
135 }
136 (sum.clone(), sum.add(&BigInt::from_i64(2 * k + 4)))
137}
138
139fn ln2_cache() -> &'static Mutex<Option<(i64, BigInt, BigInt)>> {
140 static CACHE: OnceLock<Mutex<Option<(i64, BigInt, BigInt)>>> = OnceLock::new();
141 CACHE.get_or_init(|| Mutex::new(None))
142}
143
144fn ln2_iv(p: i64) -> Iv {
146 let p = p.max(8);
147 {
148 let cache = ln2_cache().lock().expect("the ln 2 cache is never poisoned");
149 if let Some((w, lo, hi)) = cache.as_ref() {
150 if *w >= p {
151 return Iv {
152 lo: Dyadic::new(lo.clone(), -w),
153 hi: Dyadic::new(hi.clone(), -w),
154 }
155 .round_out(p);
156 }
157 }
158 }
159 let w = p + 16;
160 let (lo, hi) = atanh_scaled(&one(), &BigInt::from_i64(3), w);
161 let (lo, hi) = (lo.shl_bits(1), hi.shl_bits(1));
162 *ln2_cache().lock().expect("the ln 2 cache is never poisoned") =
163 Some((w, lo.clone(), hi.clone()));
164 Iv {
165 lo: Dyadic::new(lo, -w),
166 hi: Dyadic::new(hi, -w),
167 }
168 .round_out(p)
169}
170
171fn exp_point(x: &Dyadic, p: i64) -> Iv {
174 let s = (x.mag_bits() + 2).max(0);
175 let growth = if x.is_positive() {
176 (x.ceil_scaled(0).to_i64().unwrap_or(i64::MAX / 4) * 3 / 2).max(0)
177 } else {
178 0
179 };
180 exp_raw(x, p + s + growth + 16).round_out(p)
181}
182
183fn exp_raw(x: &Dyadic, w: i64) -> Iv {
187 let s = (x.mag_bits() + 2).max(0);
188 let y = x.shift(-s);
189 let unit = one().shl_bits(w as u64);
190 let yw = y.floor_scaled(w);
191 let mut term = unit.clone();
192 let mut sum = unit;
193 let mut k = 1i64;
194 loop {
195 term = floor_div(&term.mul(&yw), &BigInt::from_i64(k).shl_bits(w as u64));
196 if term.is_zero() {
197 break;
198 }
199 sum = sum.add(&term);
200 k += 1;
201 }
202 let err = BigInt::from_i64(2 * k + 6);
203 let mut iv = Iv {
204 lo: Dyadic::new(sum.sub(&err), -w),
205 hi: Dyadic::new(sum.add(&err), -w),
206 };
207 for _ in 0..s {
208 iv = iv.sq().round_out(w);
209 }
210 iv
211}
212
213fn log_point(x: &Dyadic, p: i64) -> Iv {
215 let k = x.m.bit_len() as i64 + x.e - 1;
216 let r = x.shift(-k);
217 let r_num = r.floor_scaled(p + 64);
218 let den = one().shl_bits((p + 64) as u64);
219 let w = p + 24;
220 let (z_lo_num, z_hi_num) = (r_num.sub(&den), r_num.add(&one()).sub(&den));
221 let (lo_scaled, _) = atanh_scaled(&z_lo_num, &r_num.add(&den), w);
222 let (_, hi_scaled) = atanh_scaled(&z_hi_num, &r_num.add(&one()).add(&den), w);
223 let log_r = Iv {
224 lo: Dyadic::new(lo_scaled.shl_bits(1), -w),
225 hi: Dyadic::new(hi_scaled.shl_bits(1), -w),
226 };
227 let kb = Iv::point(Dyadic::int(k));
228 let extra = (k.unsigned_abs() as f64).log2().ceil() as i64 + 4;
229 kb.mul(&ln2_iv(w + extra)).add(&log_r).round_out(p)
230}
231
232fn sin_cos_small(x: &Dyadic, p: i64) -> (Iv, Iv) {
234 let (s, c) = sin_cos_raw(x, p + 32);
235 (s.round_out(p), c.round_out(p))
236}
237
238fn sin_cos_raw(x: &Dyadic, w: i64) -> (Iv, Iv) {
242 let s = 4i64;
243 let y = x.shift(-s);
244 let yw = y.floor_scaled(w);
245 let scale = one().shl_bits(w as u64);
246 let mut term = yw.clone();
247 let mut sin_sum = yw.clone();
248 let mut cos_sum = scale.clone();
249 let mut cos_term = scale;
250 let mut k = 1i64;
251 loop {
252 cos_term = floor_div(
253 &cos_term.mul(&yw).mul(&yw).negated(),
254 &BigInt::from_i64((2 * k - 1) * (2 * k)).shl_bits(2 * w as u64),
255 );
256 term = floor_div(
257 &term.mul(&yw).mul(&yw).negated(),
258 &BigInt::from_i64((2 * k) * (2 * k + 1)).shl_bits(2 * w as u64),
259 );
260 if term.is_zero() && cos_term.is_zero() {
261 break;
262 }
263 sin_sum = sin_sum.add(&term);
264 cos_sum = cos_sum.add(&cos_term);
265 k += 1;
266 }
267 let err = Dyadic::new(BigInt::from_i64(2 * k + 6), -w);
268 let mut sn = Iv::point(Dyadic::new(sin_sum, -w)).widen(&err);
269 let mut cs = Iv::point(Dyadic::new(cos_sum, -w)).widen(&err);
270 let two = Iv::point(Dyadic::int(2));
271 let unit = Iv::point(Dyadic::int(1));
272 for _ in 0..s {
273 let s2 = two.mul(&sn.mul(&cs)).round_out(w);
274 let c2 = unit.add(&two.mul(&sn.sq()).neg()).round_out(w);
275 sn = s2.clamp_unit();
276 cs = c2.clamp_unit();
277 }
278 (sn, cs)
279}
280
281fn sin_cos_point(x: &Dyadic, p: i64) -> (Iv, Iv) {
285 if x.mag_bits() <= 2 {
286 return sin_cos_small(x, p);
287 }
288 let guard = x.mag_bits().max(0) + 16;
289 let two_pi = pi_iv(p + guard).mul(&Iv::point(Dyadic::int(2)));
290 let k_num = x.floor_scaled(64);
291 let approx_turns = floor_div(&k_num, &two_pi.lo.floor_scaled(64).max(BigInt::from_i64(1)));
292 let k = Iv::point(Dyadic::new(approx_turns, 0));
293 let reduced = Iv::point(x.clone()).add(&k.mul(&two_pi).neg());
294 let mid = reduced.lo.add(&reduced.hi).shift(-1);
295 let radius = reduced.width().shift(-1);
296 let (s, c) = sin_cos_small(&mid, p + 4);
297 (
298 s.widen(&radius).clamp_unit().round_out(p),
299 c.widen(&radius).clamp_unit().round_out(p),
300 )
301}
302
303fn isqrt(n: &BigInt) -> BigInt {
305 if n.is_zero() {
306 return BigInt::zero();
307 }
308 let mut x = one().shl_bits(n.bit_len() / 2 + 1);
309 loop {
310 let y = x.add(&n.div_rem(&x).expect("x > 0").0).shr_bits(1).expect("positive");
311 if y >= x {
312 return x;
313 }
314 x = y;
315 }
316}
317
318fn sqrt_floor(d: &Dyadic, p: i64) -> Dyadic {
319 Dyadic::new(isqrt(&d.floor_scaled(2 * p).max(BigInt::zero())), -p)
320}
321
322fn sqrt_ceil(d: &Dyadic, p: i64) -> Dyadic {
323 let n = d.ceil_scaled(2 * p).max(BigInt::zero());
324 let s = isqrt(&n);
325 let s = if s.mul(&s) < n { s.add(&one()) } else { s };
326 Dyadic::new(s, -p)
327}
328
329fn recip_iv(x: &Iv, p: i64) -> Iv {
331 let num = one();
332 let bound = |d: &Dyadic, up: bool| -> Dyadic {
333 let shift = p - d.e;
334 let (n, dd) = if shift >= 0 {
335 (num.shl_bits(shift as u64), d.m.clone())
336 } else {
337 (num.clone(), d.m.shl_bits((-shift) as u64))
338 };
339 let (n, dd) = if dd.is_negative() {
340 (n.negated(), dd.negated())
341 } else {
342 (n, dd)
343 };
344 let q = if up { ceil_div(&n, &dd) } else { floor_div(&n, &dd) };
345 Dyadic::new(q, -p)
346 };
347 Iv {
348 lo: bound(&x.hi, false),
349 hi: bound(&x.lo, true),
350 }
351}
352
353use crate::complex_algebraic::ComplexAlgebraic as Calg;
356
357#[derive(Clone, Debug, PartialEq, Eq, Hash)]
360struct ExpSum {
361 terms: Vec<(Calg, Calg)>,
362}
363
364impl ExpSum {
365 fn from_terms(raw: Vec<(Calg, Calg)>) -> ExpSum {
366 let mut merged: Vec<(Calg, Calg)> = Vec::new();
367 let mut raw = raw;
368 raw.sort_by(|a, b| b.0.cmp(&a.0));
369 for (e, c) in raw {
370 match merged.last_mut() {
371 Some((le, lc)) if *le == e => *lc = lc.add(&c),
372 _ => merged.push((e, c)),
373 }
374 }
375 merged.retain(|(_, c)| !c.is_zero());
376 ExpSum { terms: merged }
377 }
378
379 fn constant(a: &Algebraic) -> ExpSum {
380 ExpSum::from_terms(vec![(Calg::zero(), Calg::real(a.clone()))])
381 }
382
383 fn add(&self, o: &ExpSum) -> ExpSum {
384 ExpSum::from_terms(self.terms.iter().chain(o.terms.iter()).cloned().collect())
385 }
386
387 fn neg(&self) -> ExpSum {
388 ExpSum {
389 terms: self.terms.iter().map(|(e, c)| (e.clone(), c.neg())).collect(),
390 }
391 }
392
393 fn mul(&self, o: &ExpSum) -> ExpSum {
394 let mut raw = Vec::with_capacity(self.terms.len() * o.terms.len());
395 for (e1, c1) in &self.terms {
396 for (e2, c2) in &o.terms {
397 raw.push((e1.add(e2), c1.mul(c2)));
398 }
399 }
400 ExpSum::from_terms(raw)
401 }
402
403 fn recip(&self) -> Option<ExpSum> {
406 match self.terms.as_slice() {
407 [(e, c)] => Some(ExpSum {
408 terms: vec![(e.neg(), c.recip()?)],
409 }),
410 _ => None,
411 }
412 }
413
414 fn as_constant(&self) -> Option<Algebraic> {
416 match self.terms.as_slice() {
417 [] => Some(Algebraic::from_i64(0)),
418 [(e, c)] if e.is_zero() => Some(c.re.clone()),
419 _ => None,
420 }
421 }
422}
423
424#[derive(Clone, Debug, PartialEq, Eq, Hash)]
426struct PiPoly {
427 terms: Vec<(i32, Algebraic)>,
428}
429
430impl PiPoly {
431 fn from_terms(raw: Vec<(i32, Algebraic)>) -> PiPoly {
432 let mut raw = raw;
433 raw.sort_by_key(|t| std::cmp::Reverse(t.0));
434 let mut merged: Vec<(i32, Algebraic)> = Vec::new();
435 for (k, c) in raw {
436 match merged.last_mut() {
437 Some((lk, lc)) if *lk == k => *lc = lc.add(&c),
438 _ => merged.push((k, c)),
439 }
440 }
441 merged.retain(|(_, c)| !c.is_zero());
442 PiPoly { terms: merged }
443 }
444
445 fn constant(a: &Algebraic) -> PiPoly {
446 PiPoly::from_terms(vec![(0, a.clone())])
447 }
448
449 fn add(&self, o: &PiPoly) -> PiPoly {
450 PiPoly::from_terms(self.terms.iter().chain(o.terms.iter()).cloned().collect())
451 }
452
453 fn neg(&self) -> PiPoly {
454 PiPoly {
455 terms: self.terms.iter().map(|(k, c)| (*k, c.neg())).collect(),
456 }
457 }
458
459 fn mul(&self, o: &PiPoly) -> PiPoly {
460 let mut raw = Vec::new();
461 for (k1, c1) in &self.terms {
462 for (k2, c2) in &o.terms {
463 raw.push((k1 + k2, c1.mul(c2)));
464 }
465 }
466 PiPoly::from_terms(raw)
467 }
468
469 fn recip(&self) -> Option<PiPoly> {
470 match self.terms.as_slice() {
471 [(k, c)] => Some(PiPoly {
472 terms: vec![(-k, c.recip()?)],
473 }),
474 _ => None,
475 }
476 }
477
478 fn as_constant(&self) -> Option<Algebraic> {
479 match self.terms.as_slice() {
480 [] => Some(Algebraic::from_i64(0)),
481 [(0, c)] => Some(c.clone()),
482 _ => None,
483 }
484 }
485}
486
487struct AlgLeaf {
491 value: Algebraic,
492 cache: Mutex<Option<Iv>>,
493}
494
495enum Node {
496 Alg(AlgLeaf),
497 Pi,
498 Add(ExactReal, ExactReal),
499 Mul(ExactReal, ExactReal),
500 Neg(ExactReal),
501 Recip(ExactReal),
502 Exp(ExactReal),
503 Log(ExactReal),
504 Sin(ExactReal),
505 Cos(ExactReal),
506 Sqrt(ExactReal),
507 Flow(Arc<FlowSolution>, usize),
509 Defined(Arc<Defined>),
511}
512
513pub trait Approximant: Send + Sync {
519 fn call(&self, n: u64) -> Result<Rational, String>;
522}
523
524#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
526pub enum Definition {
527 Digits { base: u32 },
530 Approximations,
532}
533
534impl Definition {
535 pub fn named(kind: &str, base: i64) -> Result<Definition, String> {
538 match kind {
539 "digits" => u32::try_from(base)
540 .ok()
541 .filter(|b| *b >= 2)
542 .map(|base| Definition::Digits { base })
543 .ok_or_else(|| format!("a real number's digits are in a base from 2 up, got {base}")),
544 "approximations" => Ok(Definition::Approximations),
545 other => Err(format!(
546 "a real number is defined by its digits or its approximations, got {other}"
547 )),
548 }
549 }
550}
551
552pub const STAYS_WITH_ITS_PROGRAM: &str = "a real number a function of the program defines";
555
556pub fn not_sendable() -> String {
559 format!("cannot send value through a channel: NotSendable({STAYS_WITH_ITS_PROGRAM:?})")
560}
561
562pub fn not_a_rational_answer(name: &str, n: u64, type_name: &str) -> String {
564 format!("{name}({n}) is {type_name}, and a real number is defined by whole or rational answers")
565}
566
567enum Known {
569 Digits(Vec<u32>),
571 Approximations(Vec<(u32, Rational)>),
573}
574
575pub(crate) struct Defined {
577 name: String,
579 definition: Definition,
580 source: Arc<dyn Approximant>,
581 known: Mutex<Known>,
582}
583
584fn two_to_minus(n: u32) -> Rational {
586 Rational::new(one(), one().shl_bits(u64::from(n))).expect("a power of two is nonzero")
587}
588
589impl Defined {
590 fn describe(&self) -> String {
591 match self.definition {
592 Definition::Digits { base } => {
593 format!("the real number whose digits in base {base} are {}", self.name)
594 }
595 Definition::Approximations => format!("the real number approximated by {}", self.name),
596 }
597 }
598
599 fn enclose(&self, p: i64) -> Result<Iv, RealError> {
603 match self.definition {
604 Definition::Digits { base } => self.enclose_digits(base, p),
605 Definition::Approximations => self.enclose_approximations(p),
606 }
607 }
608
609 fn digits(&self, base: u32, count: usize) -> Result<Vec<u32>, RealError> {
611 loop {
612 let next = match &*self.known.lock().expect("unpoisoned") {
613 Known::Digits(d) if d.len() >= count => return Ok(d[..count].to_vec()),
614 Known::Digits(d) => d.len(),
615 Known::Approximations(_) => unreachable!("a real defined by digits reads digits"),
616 };
617 let answer = self.source.call(next as u64).map_err(RealError::Domain)?;
618 let digit = answer
619 .to_bigint()
620 .filter(|_| answer.is_integer())
621 .and_then(|d| d.to_u64())
622 .filter(|d| *d < u64::from(base))
623 .ok_or_else(|| {
624 RealError::Domain(format!(
625 "digit {next} of {} is {answer}: a digit in base {base} is a whole number from 0 to {}",
626 self.describe(),
627 base - 1
628 ))
629 })?;
630 if let Known::Digits(d) = &mut *self.known.lock().expect("unpoisoned") {
631 if d.len() == next {
632 d.push(digit as u32);
633 }
634 }
635 }
636 }
637
638 fn enclose_digits(&self, base: u32, p: i64) -> Result<Iv, RealError> {
640 let b = Rational::from_i64(i64::from(base));
641 let mut places = 0usize;
642 let mut tail = Rational::from_i64(1);
643 let bound = two_to_minus(u32::try_from((p + 2).max(0)).unwrap_or(u32::MAX));
644 while tail > bound {
645 tail = tail.div(&b).expect("a base is positive");
646 places += 1;
647 }
648 let digits = self.digits(base, places + 1)?;
649 let mut sum = Rational::zero();
650 let mut weight = Rational::from_i64(1);
651 for d in &digits {
652 sum = sum.add(&weight.mul(&Rational::from_i64(i64::from(*d))));
653 weight = weight.div(&b).expect("a base is positive");
654 }
655 Ok(Iv {
656 lo: Dyadic::from_rational_floor(&sum, p + 2),
657 hi: Dyadic::from_rational_ceil(&sum.add(&tail), p + 2),
658 })
659 }
660
661 fn enclose_approximations(&self, p: i64) -> Result<Iv, RealError> {
665 let n = u32::try_from((p + 2).max(0)).unwrap_or(u32::MAX);
666 let known = match &*self.known.lock().expect("unpoisoned") {
667 Known::Approximations(made) => made.iter().find(|(m, _)| *m == n).map(|(_, q)| q.clone()),
668 Known::Digits(_) => unreachable!("a real defined by approximations reads approximations"),
669 };
670 let q = match known {
671 Some(q) => q,
672 None => {
673 let q = self.source.call(u64::from(n)).map_err(RealError::Domain)?;
674 if let Known::Approximations(made) = &mut *self.known.lock().expect("unpoisoned") {
675 for (m, r) in made.iter() {
676 if q.sub(r).abs() > two_to_minus(n).add(&two_to_minus(*m)) {
677 return Err(RealError::Domain(format!(
678 "{name}({n}) is {q} and {name}({m}) is {r}, further apart than 2^-{n} + 2^-{m}: \
679 {name} approximates no one real number",
680 name = self.name
681 )));
682 }
683 }
684 if !made.iter().any(|(m, _)| *m == n) {
685 made.push((n, q.clone()));
686 }
687 }
688 q
689 }
690 };
691 let eps = two_to_minus(n);
692 Ok(Iv {
693 lo: Dyadic::from_rational_floor(&q.sub(&eps), p + 2),
694 hi: Dyadic::from_rational_ceil(&q.add(&eps), p + 2),
695 })
696 }
697}
698
699pub(crate) struct FlowSolution {
701 field: Field,
702 start: Vec<ExactReal>,
703 t: Rational,
704 cache: Mutex<Option<(i64, Vec<Iv>)>>,
706}
707
708impl fmt::Debug for FlowSolution {
709 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
710 write!(f, "FlowSolution(t = {}, {} components)", self.t, self.start.len())
711 }
712}
713
714impl FlowSolution {
715 fn enclose(&self, i: usize, p: i64, cap: i64) -> Result<Iv, RealError> {
717 let within = |iv: &Iv| iv.width().mag_bits() <= -(p + 2);
718 if let Some((_, ivs)) = self.cache.lock().expect("unpoisoned").as_ref() {
719 if within(&ivs[i]) {
720 return Ok(ivs[i].round_out(p + 2));
721 }
722 }
723 let mut q = (p + 32).max(64);
724 loop {
725 let start = self
726 .start
727 .iter()
728 .map(|x| x.enclosed(q + 8, cap))
729 .collect::<Result<Vec<Iv>, RealError>>()?;
730 match crate::ode::flow(&self.field, &start, &self.t, q, (q / 2).max(40)) {
731 Ok(ivs) => {
732 let done = within(&ivs[i]);
733 let answer = ivs[i].round_out(p + 2);
734 *self.cache.lock().expect("unpoisoned") = Some((q, ivs));
735 if done {
736 return Ok(answer);
737 }
738 }
739 Err(FlowError::Escapes) => {
740 return Err(RealError::Domain(
741 "the solution of the flow leaves every bound before its time".to_string(),
742 ))
743 }
744 Err(FlowError::Shape) => {
745 return Err(RealError::Domain(
746 "a flow's field and its start disagree in shape".to_string(),
747 ))
748 }
749 }
750 if q >= cap {
751 return Err(RealError::Inseparable {
752 what: "the solution of the flow".to_string(),
753 bits: cap as u32,
754 });
755 }
756 q = (q * 2).min(cap);
757 }
758 }
759}
760
761fn poly_sign_at(min: &[BigInt], d: &Dyadic) -> Ordering {
763 let k = (-d.e).max(0);
764 let m = if d.e > 0 { d.m.shl_bits(d.e as u64) } else { d.m.clone() };
765 let deg = min.len() - 1;
766 let mut acc = BigInt::zero();
767 let mut mp = one();
768 for (i, c) in min.iter().enumerate() {
769 acc = acc.add(&c.mul(&mp).shl_bits((k as u64) * (deg - i) as u64));
770 mp = mp.mul(&m);
771 }
772 acc.cmp(&BigInt::zero())
773}
774
775impl AlgLeaf {
776 fn enclose(&self, p: i64) -> Iv {
781 if let Some(r) = self.value.to_rational() {
782 return Iv {
783 lo: Dyadic::from_rational_floor(&r, p),
784 hi: Dyadic::from_rational_ceil(&r, p),
785 };
786 }
787 let min_poly = self.value.minimal_polynomial();
788 let min = min_poly.primitive_int();
789 let mut cache = self.cache.lock().expect("an algebraic leaf cache is never poisoned");
790 let mut iv = match cache.take() {
791 Some(iv) => iv,
792 None => {
793 let (lo, hi) = self.value.enclosure(8);
794 let lo_sign = min_poly.eval(&lo).cmp(&Rational::zero());
795 let hi_sign = min_poly.eval(&hi).cmp(&Rational::zero());
796 let mut k = 16i64;
797 loop {
798 let dlo = Dyadic::from_rational_ceil(&lo, k);
799 let dhi = Dyadic::from_rational_floor(&hi, k);
800 if dlo.cmp(&dhi) == Ordering::Less
801 && poly_sign_at(&min, &dlo) == lo_sign
802 && poly_sign_at(&min, &dhi) == hi_sign
803 {
804 break Iv { lo: dlo, hi: dhi };
805 }
806 k *= 2;
807 }
808 }
809 };
810 let eps = Dyadic::new(one(), -p);
811 let lo_sign = poly_sign_at(&min, &iv.lo);
812 while iv.width().cmp(&eps) == Ordering::Greater {
813 let mid = iv.lo.add(&iv.hi).shift(-1);
814 let s = poly_sign_at(&min, &mid);
815 if s == Ordering::Equal {
816 iv = Iv::point(mid);
817 break;
818 }
819 if s == lo_sign {
820 iv.lo = mid;
821 } else {
822 iv.hi = mid;
823 }
824 }
825 *cache = Some(iv.clone());
826 iv
827 }
828}
829
830impl Node {
831 fn enclose(&self, p: i64, cap: i64) -> Result<Iv, RealError> {
833 match self {
834 Node::Alg(leaf) => Ok(leaf.enclose(p + 2)),
835 Node::Pi => Ok(pi_iv(p + 2)),
836 Node::Add(a, b) => {
837 Ok(a.enclosed(p + 2, cap)?.add(&b.enclosed(p + 2, cap)?).round_out(p + 1))
838 }
839 Node::Neg(a) => Ok(a.enclosed(p, cap)?.neg()),
840 Node::Mul(a, b) => {
841 let ma = a.enclosed(4, cap)?.mag_bits().max(0);
842 let mb = b.enclosed(4, cap)?.mag_bits().max(0);
843 let x = a.enclosed(p + mb + 4, cap)?;
844 let y = b.enclosed(p + ma + 4, cap)?;
845 Ok(x.mul(&y).round_out(p + 2))
846 }
847 Node::Recip(a) => {
848 let mut q = p.max(8);
849 loop {
850 let x = a.enclosed(q, cap)?;
851 if !x.contains_zero() {
852 let nearest = if x.lo.is_positive() { x.lo.clone() } else { x.hi.neg() };
853 let lower = 1 - nearest.mag_bits();
854 let need = p + 2 * lower.max(0) + 6;
855 if q >= need {
856 return Ok(recip_iv(&x, p + 2));
857 }
858 q = need;
859 continue;
860 }
861 if q >= cap {
862 return Err(RealError::Inseparable {
863 what: "the divisor from zero".to_string(),
864 bits: cap as u32,
865 });
866 }
867 q = (q * 2).min(cap);
868 }
869 }
870 Node::Exp(a) => {
871 let rough = a.enclosed(4, cap)?;
872 let growth = if rough.hi.is_positive() {
873 rough.hi.ceil_scaled(0).to_i64().unwrap_or(i64::MAX / 8) * 3 / 2 + 2
874 } else {
875 2
876 };
877 let x = a.enclosed(p + growth, cap)?;
878 Ok(Iv {
879 lo: exp_point(&x.lo, p + 4).lo,
880 hi: exp_point(&x.hi, p + 4).hi,
881 })
882 }
883 Node::Log(a) => {
884 let mut q = p.max(8);
885 loop {
886 let x = a.enclosed(q, cap)?;
887 if x.hi.is_negative() || (x.hi.m.is_zero() && x.lo.m.is_zero()) {
888 return Err(RealError::Domain(
889 "logarithm of a nonpositive number".to_string(),
890 ));
891 }
892 if x.lo.is_positive() {
893 let lower = 1 - x.lo.mag_bits();
894 let need = p + lower.max(0) + 6;
895 if q >= need {
896 return Ok(Iv {
897 lo: log_point(&x.lo, p + 4).lo,
898 hi: log_point(&x.hi, p + 4).hi,
899 });
900 }
901 q = need;
902 continue;
903 }
904 if q >= cap {
905 return Err(RealError::Inseparable {
906 what: "the logarithm's argument from zero".to_string(),
907 bits: cap as u32,
908 });
909 }
910 q = (q * 2).min(cap);
911 }
912 }
913 Node::Sqrt(a) => {
914 let mut q = p.max(8);
915 loop {
916 let x = a.enclosed(q, cap)?;
917 if x.hi.is_negative() {
918 return Err(RealError::Domain(
919 "square root of a negative number".to_string(),
920 ));
921 }
922 if x.lo.is_positive() {
923 let lower = 1 - x.lo.mag_bits();
924 let need = p + lower.max(0) + 6;
925 if q >= need {
926 return Ok(Iv {
927 lo: sqrt_floor(&x.lo, p + 2),
928 hi: sqrt_ceil(&x.hi, p + 2),
929 });
930 }
931 q = need;
932 continue;
933 }
934 if q >= cap {
935 return Err(RealError::Inseparable {
936 what: "the square root's argument from zero".to_string(),
937 bits: cap as u32,
938 });
939 }
940 q = (q * 2).min(cap);
941 }
942 }
943 Node::Flow(solution, i) => solution.enclose(*i, p, cap),
944 Node::Defined(d) => d.enclose(p),
945 Node::Sin(a) | Node::Cos(a) => {
946 let x = a.enclosed(p + 2, cap)?;
947 let mid = x.lo.add(&x.hi).shift(-1);
948 let radius = x.width().shift(-1);
949 let (s, c) = sin_cos_point(&mid, p + 4);
950 let v = if matches!(self, Node::Sin(_)) { s } else { c };
951 Ok(v.widen(&radius).clamp_unit().round_out(p + 2))
952 }
953 }
954 }
955}
956
957#[derive(Clone)]
960enum Form {
961 Alg(Algebraic),
962 Exp(ExpSum),
963 Pi(PiPoly),
964 General(Arc<Node>),
965}
966
967#[derive(Clone)]
969pub struct ExactReal {
970 form: Form,
971 tree: Arc<OnceLock<Arc<Node>>>,
972 best: Arc<Mutex<Option<(i64, Iv)>>>,
976}
977
978pub const DISPLAY_DIGITS: u32 = 30;
980
981pub const DEFAULT_BUDGET: u32 = 4096;
983
984fn half_real() -> ExactReal {
985 ExactReal::from_rational(Rational::from_ratio_i64(1, 2).expect("2 ≠ 0"))
986}
987
988impl ExactReal {
989 fn of(form: Form) -> ExactReal {
990 let form = match form {
991 Form::Exp(s) => match s.as_constant() {
992 Some(a) => Form::Alg(a),
993 None => Form::Exp(s),
994 },
995 Form::Pi(p) => match p.as_constant() {
996 Some(a) => Form::Alg(a),
997 None => Form::Pi(p),
998 },
999 other => other,
1000 };
1001 ExactReal {
1002 form,
1003 tree: Arc::new(OnceLock::new()),
1004 best: Arc::new(Mutex::new(None)),
1005 }
1006 }
1007
1008 fn enclosed(&self, p: i64, cap: i64) -> Result<Iv, RealError> {
1011 if let Some((q, iv)) = self.best.lock().expect("unpoisoned").as_ref() {
1012 if *q >= p {
1013 return Ok(iv.clone());
1014 }
1015 }
1016 let iv = self.node().enclose(p, cap)?;
1017 let mut best = self.best.lock().expect("unpoisoned");
1018 if best.as_ref().is_none_or(|(q, _)| *q < p) {
1019 *best = Some((p, iv.clone()));
1020 }
1021 Ok(iv)
1022 }
1023
1024 fn general(node: Node) -> ExactReal {
1025 ExactReal::of(Form::General(Arc::new(node)))
1026 }
1027
1028 pub fn from_i64(n: i64) -> ExactReal {
1029 Self::from_algebraic(Algebraic::from_i64(n))
1030 }
1031
1032 pub fn from_rational(r: Rational) -> ExactReal {
1033 Self::from_algebraic(Algebraic::from_rational(r))
1034 }
1035
1036 pub fn from_algebraic(a: Algebraic) -> ExactReal {
1037 Self::of(Form::Alg(a))
1038 }
1039
1040 pub fn from_f64(f: f64) -> Option<ExactReal> {
1042 rational_from_f64_exact(f).map(Self::from_rational)
1043 }
1044
1045 pub fn pi() -> ExactReal {
1046 Self::of(Form::Pi(PiPoly {
1047 terms: vec![(1, Algebraic::from_i64(1))],
1048 }))
1049 }
1050
1051 pub fn e() -> ExactReal {
1052 Self::from_i64(1).exp()
1053 }
1054
1055 pub fn exact_algebraic(&self) -> Option<Algebraic> {
1057 match &self.form {
1058 Form::Alg(a) => Some(a.clone()),
1059 _ => None,
1060 }
1061 }
1062
1063 pub fn is_exactly_zero(&self) -> bool {
1065 matches!(&self.form, Form::Alg(a) if a.is_zero())
1066 }
1067
1068 pub fn is_exact_form(&self) -> bool {
1070 !matches!(&self.form, Form::General(_))
1071 }
1072
1073 fn exp_sum(&self) -> Option<ExpSum> {
1074 match &self.form {
1075 Form::Alg(a) => Some(ExpSum::constant(a)),
1076 Form::Exp(s) => Some(s.clone()),
1077 _ => None,
1078 }
1079 }
1080
1081 fn pi_poly(&self) -> Option<PiPoly> {
1082 match &self.form {
1083 Form::Alg(a) => Some(PiPoly::constant(a)),
1084 Form::Pi(p) => Some(p.clone()),
1085 _ => None,
1086 }
1087 }
1088
1089 fn sum_of(terms: Vec<ExactReal>) -> ExactReal {
1090 terms
1091 .into_iter()
1092 .reduce(|acc, t| ExactReal::general(Node::Add(acc, t)))
1093 .unwrap_or_else(|| ExactReal::from_i64(0))
1094 }
1095
1096 fn product_of(factors: Vec<ExactReal>) -> ExactReal {
1097 factors
1098 .into_iter()
1099 .reduce(|acc, t| ExactReal::general(Node::Mul(acc, t)))
1100 .unwrap_or_else(|| ExactReal::from_i64(1))
1101 }
1102
1103 fn node(&self) -> Arc<Node> {
1105 self.tree
1106 .get_or_init(|| match &self.form {
1107 Form::General(n) => n.clone(),
1108 Form::Alg(a) => Arc::new(Node::Alg(AlgLeaf {
1109 value: a.clone(),
1110 cache: Mutex::new(None),
1111 })),
1112 Form::Pi(p) => {
1113 let terms = p
1114 .terms
1115 .iter()
1116 .map(|(k, c)| {
1117 let base = if *k >= 0 {
1118 ExactReal::general(Node::Pi)
1119 } else {
1120 ExactReal::general(Node::Recip(ExactReal::general(Node::Pi)))
1121 };
1122 let mut factors = vec![ExactReal::from_algebraic(c.clone())];
1123 factors.extend((0..k.unsigned_abs()).map(|_| base.clone()));
1124 ExactReal::product_of(factors)
1125 })
1126 .collect();
1127 ExactReal::sum_of(terms).node()
1128 }
1129 Form::Exp(s) => {
1130 let terms = s
1131 .terms
1132 .iter()
1133 .map(|(e, c)| {
1134 let mut factors = Vec::new();
1135 if !e.re.is_zero() {
1136 factors.push(ExactReal::general(Node::Exp(
1137 ExactReal::from_algebraic(e.re.clone()),
1138 )));
1139 }
1140 if e.im.is_zero() {
1141 factors.push(ExactReal::from_algebraic(c.re.clone()));
1142 } else {
1143 let v = ExactReal::from_algebraic(e.im.clone());
1144 let mut parts = Vec::new();
1145 if !c.re.is_zero() {
1146 parts.push(ExactReal::product_of(vec![
1147 ExactReal::from_algebraic(c.re.clone()),
1148 ExactReal::general(Node::Cos(v.clone())),
1149 ]));
1150 }
1151 if !c.im.is_zero() {
1152 parts.push(ExactReal::product_of(vec![
1153 ExactReal::from_algebraic(c.im.neg()),
1154 ExactReal::general(Node::Sin(v)),
1155 ]));
1156 }
1157 factors.push(ExactReal::sum_of(parts));
1158 }
1159 ExactReal::product_of(factors)
1160 })
1161 .collect();
1162 ExactReal::sum_of(terms).node()
1163 }
1164 })
1165 .clone()
1166 }
1167
1168 pub fn add(&self, o: &ExactReal) -> ExactReal {
1169 if let (Form::Alg(a), Form::Alg(b)) = (&self.form, &o.form) {
1170 return Self::from_algebraic(a.add(b));
1171 }
1172 if let (Some(a), Some(b)) = (self.exp_sum(), o.exp_sum()) {
1173 return Self::of(Form::Exp(a.add(&b)));
1174 }
1175 if let (Some(a), Some(b)) = (self.pi_poly(), o.pi_poly()) {
1176 return Self::of(Form::Pi(a.add(&b)));
1177 }
1178 Self::general(Node::Add(self.clone(), o.clone()))
1179 }
1180
1181 pub fn neg(&self) -> ExactReal {
1182 match &self.form {
1183 Form::Alg(a) => Self::from_algebraic(a.neg()),
1184 Form::Exp(s) => Self::of(Form::Exp(s.neg())),
1185 Form::Pi(p) => Self::of(Form::Pi(p.neg())),
1186 Form::General(_) => Self::general(Node::Neg(self.clone())),
1187 }
1188 }
1189
1190 pub fn sub(&self, o: &ExactReal) -> ExactReal {
1191 self.add(&o.neg())
1192 }
1193
1194 pub fn mul(&self, o: &ExactReal) -> ExactReal {
1195 if let (Form::Alg(a), Form::Alg(b)) = (&self.form, &o.form) {
1196 return Self::from_algebraic(a.mul(b));
1197 }
1198 if let (Some(a), Some(b)) = (self.exp_sum(), o.exp_sum()) {
1199 return Self::of(Form::Exp(a.mul(&b)));
1200 }
1201 if let (Some(a), Some(b)) = (self.pi_poly(), o.pi_poly()) {
1202 return Self::of(Form::Pi(a.mul(&b)));
1203 }
1204 Self::general(Node::Mul(self.clone(), o.clone()))
1205 }
1206
1207 pub fn recip(&self) -> Result<ExactReal, RealError> {
1210 if self.is_exactly_zero() {
1211 return Err(RealError::Domain("division by zero".to_string()));
1212 }
1213 Ok(match &self.form {
1214 Form::Alg(a) => Self::from_algebraic(a.recip().expect("nonzero")),
1215 Form::Exp(s) => match s.recip() {
1216 Some(r) => Self::of(Form::Exp(r)),
1217 None => Self::general(Node::Recip(self.clone())),
1218 },
1219 Form::Pi(p) => match p.recip() {
1220 Some(r) => Self::of(Form::Pi(r)),
1221 None => Self::general(Node::Recip(self.clone())),
1222 },
1223 Form::General(_) => Self::general(Node::Recip(self.clone())),
1224 })
1225 }
1226
1227 pub fn div(&self, o: &ExactReal) -> Result<ExactReal, RealError> {
1228 Ok(self.mul(&o.recip()?))
1229 }
1230
1231 pub fn pow(&self, k: i32) -> Option<ExactReal> {
1233 if k < 0 {
1234 return self.recip().ok()?.pow(-k);
1235 }
1236 if let Form::Alg(a) = &self.form {
1237 return a.pow(k).map(Self::from_algebraic);
1238 }
1239 let mut acc = Self::from_i64(1);
1240 let mut base = self.clone();
1241 let mut e = k as u32;
1242 while e > 0 {
1243 if e & 1 == 1 {
1244 acc = acc.mul(&base);
1245 }
1246 e >>= 1;
1247 if e > 0 {
1248 base = base.mul(&base);
1249 }
1250 }
1251 Some(acc)
1252 }
1253
1254 pub fn defined(definition: Definition, name: &str, source: Arc<dyn Approximant>) -> ExactReal {
1258 let known = match definition {
1259 Definition::Digits { .. } => Known::Digits(Vec::new()),
1260 Definition::Approximations => Known::Approximations(Vec::new()),
1261 };
1262 ExactReal::general(Node::Defined(Arc::new(Defined {
1263 name: name.to_string(),
1264 definition,
1265 source,
1266 known: Mutex::new(known),
1267 })))
1268 }
1269
1270 pub fn is_transmissible(&self) -> bool {
1273 match &self.form {
1274 Form::General(n) => n.is_transmissible(),
1275 _ => true,
1276 }
1277 }
1278
1279 pub fn flow(field: &Field, start: &[ExactReal], t: &Rational) -> Option<Vec<ExactReal>> {
1283 if start.is_empty()
1284 || start.len() != field.dimension()
1285 || field.components.iter().any(|c| c.iter().any(|m| m.powers.len() != start.len()))
1286 || t.is_negative()
1287 {
1288 return None;
1289 }
1290 let solution = Arc::new(FlowSolution {
1291 field: field.clone(),
1292 start: start.to_vec(),
1293 t: t.clone(),
1294 cache: Mutex::new(None),
1295 });
1296 Some(
1297 (0..start.len())
1298 .map(|i| ExactReal::general(Node::Flow(solution.clone(), i)))
1299 .collect(),
1300 )
1301 }
1302
1303 pub fn sqrt(&self) -> Result<ExactReal, RealError> {
1305 self.nth_root(2)
1306 }
1307
1308 pub fn nth_root(&self, n: u32) -> Result<ExactReal, RealError> {
1313 assert!(n >= 1, "a root has a positive index");
1314 if n == 1 {
1315 return Ok(self.clone());
1316 }
1317 let refused = || RealError::Domain(negative_root(n));
1318 match &self.form {
1319 Form::Alg(a) => return a.nth_root(n).map(Self::from_algebraic).ok_or_else(refused),
1320 Form::Exp(s) => {
1321 if let [(e, c)] = s.terms.as_slice() {
1322 if e.is_real() && c.is_real() {
1323 let root = c.re.nth_root(n).ok_or_else(refused)?;
1324 let beta = e.re.div(&Algebraic::from_i64(i64::from(n))).expect("n ≥ 1");
1325 return Ok(Self::of(Form::Exp(ExpSum::from_terms(vec![(
1326 Calg::real(beta),
1327 Calg::real(root),
1328 )]))));
1329 }
1330 }
1331 }
1332 _ => {}
1333 }
1334 if n == 2 {
1335 return Ok(Self::general(Node::Sqrt(self.clone())));
1336 }
1337 let index = Self::from_rational(Rational::from_ratio_i64(1, i64::from(n)).expect("n ≥ 1"));
1338 match self.compare(&Self::from_i64(0), DEFAULT_BUDGET)? {
1339 Ordering::Equal => Ok(Self::from_i64(0)),
1340 Ordering::Greater => Ok(self.log()?.mul(&index).exp()),
1341 Ordering::Less if n % 2 == 0 => Err(refused()),
1342 Ordering::Less => Ok(self.neg().log()?.mul(&index).exp().neg()),
1343 }
1344 }
1345
1346 pub fn exp(&self) -> ExactReal {
1347 match &self.form {
1348 Form::Alg(a) if a.is_zero() => Self::from_i64(1),
1349 Form::Alg(a) => Self::of(Form::Exp(ExpSum::from_terms(vec![(
1350 Calg::real(a.clone()),
1351 Calg::real(Algebraic::from_i64(1)),
1352 )]))),
1353 Form::General(n) => match n.as_ref() {
1354 Node::Log(inner) => inner.clone(),
1355 _ => Self::general(Node::Exp(self.clone())),
1356 },
1357 _ => Self::general(Node::Exp(self.clone())),
1358 }
1359 }
1360
1361 pub fn log(&self) -> Result<ExactReal, RealError> {
1364 match &self.form {
1365 Form::Alg(a) if a.signum() <= 0 => Err(RealError::Domain(
1366 "logarithm of a nonpositive number".to_string(),
1367 )),
1368 Form::Alg(a) if *a == Algebraic::from_i64(1) => Ok(Self::from_i64(0)),
1369 Form::Exp(s) => match s.terms.as_slice() {
1370 [(e, c)] if e.is_real() && c.is_real() && c.re.signum() > 0 => {
1371 let beta = Self::from_algebraic(e.re.clone());
1372 if c.re == Algebraic::from_i64(1) {
1373 Ok(beta)
1374 } else {
1375 Ok(beta.add(&Self::from_algebraic(c.re.clone()).log()?))
1376 }
1377 }
1378 _ => Ok(Self::general(Node::Log(self.clone()))),
1379 },
1380 Form::General(n) => match n.as_ref() {
1381 Node::Exp(inner) => Ok(inner.clone()),
1382 _ => Ok(Self::general(Node::Log(self.clone()))),
1383 },
1384 _ => Ok(Self::general(Node::Log(self.clone()))),
1385 }
1386 }
1387
1388 fn trig(&self, sine: bool) -> ExactReal {
1389 match &self.form {
1390 Form::Alg(a) if a.is_zero() => Self::from_i64(if sine { 0 } else { 1 }),
1391 Form::Alg(a) => {
1392 let half = Algebraic::from_rational(Rational::from_ratio_i64(1, 2).expect("2 ≠ 0"));
1393 let plus = Calg::imag(a.clone());
1394 let minus = Calg::imag(a.neg());
1395 let terms = if sine {
1396 vec![(plus, Calg::imag(half.neg())), (minus, Calg::imag(half))]
1397 } else {
1398 vec![(plus, Calg::real(half.clone())), (minus, Calg::real(half))]
1399 };
1400 Self::of(Form::Exp(ExpSum::from_terms(terms)))
1401 }
1402 _ => Self::general(if sine {
1403 Node::Sin(self.clone())
1404 } else {
1405 Node::Cos(self.clone())
1406 }),
1407 }
1408 }
1409
1410 pub fn sin(&self) -> ExactReal {
1411 self.trig(true)
1412 }
1413
1414 pub fn cos(&self) -> ExactReal {
1415 self.trig(false)
1416 }
1417
1418 pub fn cosh(&self) -> ExactReal {
1419 self.exp().add(&self.neg().exp()).mul(&half_real())
1420 }
1421
1422 pub fn sinh(&self) -> ExactReal {
1423 self.exp().sub(&self.neg().exp()).mul(&half_real())
1424 }
1425
1426 pub fn enclosure(&self, bits: u32) -> Result<(Rational, Rational), RealError> {
1428 let iv = self.enclose_width(bits as i64, Self::cap_for(bits))?;
1429 Ok((iv.lo.to_rational(), iv.hi.to_rational()))
1430 }
1431
1432 fn cap_for(bits: u32) -> i64 {
1433 4 * bits as i64 + DEFAULT_BUDGET as i64
1434 }
1435
1436 fn enclose_width(&self, bits: i64, cap: i64) -> Result<Iv, RealError> {
1438 if let Form::Alg(a) = &self.form {
1439 if let Some(r) = a.to_rational() {
1440 return Ok(Iv {
1441 lo: Dyadic::from_rational_floor(&r, bits + 2),
1442 hi: Dyadic::from_rational_ceil(&r, bits + 2),
1443 });
1444 }
1445 }
1446 let eps = Dyadic::new(one(), -bits);
1447 let mut p = bits + 8;
1448 loop {
1449 let iv = self.enclosed(p, cap)?;
1450 if iv.width().cmp(&eps) != Ordering::Greater {
1451 return Ok(iv);
1452 }
1453 if p >= cap {
1454 return Err(RealError::Inseparable {
1455 what: format!("an enclosure of {} narrower than 2^-{bits}", self.describe()),
1456 bits: cap as u32,
1457 });
1458 }
1459 p = (p + p / 2 + 16).min(cap);
1460 }
1461 }
1462
1463 pub fn compare(&self, o: &ExactReal, budget: u32) -> Result<Ordering, RealError> {
1468 let d = self.sub(o);
1469 if d.is_exactly_zero() {
1470 return Ok(Ordering::Equal);
1471 }
1472 let cap = if d.is_exact_form() { i64::MAX / 4 } else { budget as i64 };
1473 let mut p = 8i64;
1474 loop {
1475 let iv = d.enclosed(p, cap.max(p))?;
1476 if iv.lo.is_positive() {
1477 return Ok(Ordering::Greater);
1478 }
1479 if iv.hi.is_negative() {
1480 return Ok(Ordering::Less);
1481 }
1482 if p >= cap {
1483 return Err(RealError::Inseparable {
1484 what: format!("{} and {}", self.describe(), o.describe()),
1485 bits: budget,
1486 });
1487 }
1488 p = (p * 2).min(cap);
1489 }
1490 }
1491
1492 pub fn compare_within(&self, o: &ExactReal, tolerance: &Rational) -> Result<Closeness, RealError> {
1498 let d = self.sub(o);
1499 if d.is_exactly_zero() {
1500 return Ok(Closeness::Close);
1501 }
1502 let quarter = tolerance.mul(&Rational::from_ratio_i64(1, 4).expect("4 ≠ 0"));
1503 let mut bits = 1i64;
1504 while Rational::new(one(), one().shl_bits(bits as u64)).expect("nonzero") > quarter {
1505 bits += 1;
1506 }
1507 let tol = Dyadic::from_rational_floor(tolerance, bits + 4);
1508 let iv = d.enclose_width(bits, Self::cap_for(bits as u32))?;
1509 Ok(
1510 if iv.lo.cmp(&tol.neg()) != Ordering::Less && iv.hi.cmp(&tol) != Ordering::Greater {
1511 Closeness::Close
1512 } else if iv.lo.is_positive() {
1513 Closeness::Greater
1514 } else {
1515 Closeness::Less
1516 },
1517 )
1518 }
1519
1520 pub fn floor(&self, budget: u32) -> Result<BigInt, RealError> {
1523 if let Form::Alg(a) = &self.form {
1524 return Ok(a.floor());
1525 }
1526 let mut p = 8i64;
1527 loop {
1528 let iv = self.enclosed(p, (budget as i64).max(p))?;
1529 let (fl, fh) = (iv.lo.floor_scaled(0), iv.hi.floor_scaled(0));
1530 if fl == fh {
1531 return Ok(fl);
1532 }
1533 if p >= budget as i64 {
1534 return Err(RealError::Inseparable {
1535 what: format!("{} from the integer {fh}", self.describe()),
1536 bits: budget,
1537 });
1538 }
1539 p = (p * 2).min(budget as i64);
1540 }
1541 }
1542
1543 fn scaled_round(&self, k: i64) -> Result<BigInt, RealError> {
1546 let ten_k = Rational::from_bigint(BigInt::from_i64(10).pow(k.unsigned_abs() as u32));
1547 let scale = |r: Rational| -> Rational {
1548 if k >= 0 {
1549 r.mul(&ten_k)
1550 } else {
1551 r.div(&ten_k).expect("10^k ≠ 0")
1552 }
1553 };
1554 if let Some(r) = self.exact_algebraic().and_then(|a| a.to_rational()) {
1555 return Ok(scale(r.abs()).round());
1556 }
1557 let half = Rational::from_ratio_i64(1, 2).expect("2 ≠ 0");
1558 let digits_bits = (k.max(0) as f64 * std::f64::consts::LOG2_10).ceil() as i64;
1559 let cap = Self::cap_for(digits_bits as u32 + 64);
1560 let mut p = 16 + digits_bits;
1561 loop {
1562 let iv = self.enclosed(p, cap.max(p))?;
1563 let (lo, hi) = if !iv.hi.is_positive() {
1564 (iv.hi.neg(), iv.lo.neg())
1565 } else {
1566 (iv.lo.clone(), iv.hi.clone())
1567 };
1568 if !lo.is_negative() {
1569 let a = scale(lo.to_rational()).add(&half).floor();
1570 let b = scale(hi.to_rational()).add(&half).floor();
1571 if a == b {
1572 return Ok(a);
1573 }
1574 }
1575 if p >= cap {
1576 return Err(RealError::Inseparable {
1577 what: format!("{} from a rounding boundary", self.describe()),
1578 bits: cap as u32,
1579 });
1580 }
1581 p = (p + p / 2 + 16).min(cap);
1582 }
1583 }
1584
1585 pub fn to_decimal(&self, sig: u32) -> String {
1588 self.try_to_decimal(sig).unwrap_or_else(|e| format!("⟨{e}⟩"))
1589 }
1590
1591 pub fn try_to_decimal(&self, sig: u32) -> Result<String, RealError> {
1594 if self.is_exactly_zero() {
1595 return Ok("0".to_string());
1596 }
1597 let sig = sig.max(1) as i64;
1598 let zero = Self::from_i64(0);
1599 let negative = self.compare(&zero, DEFAULT_BUDGET)? == Ordering::Less;
1600 let abs = if negative { self.neg() } else { self.clone() };
1601 let mut exp10 = abs.decimal_exponent()?;
1602 let digits = loop {
1603 let text = abs.scaled_round(sig - 1 - exp10)?.to_string();
1604 if text.len() as i64 > sig {
1605 exp10 += 1;
1606 continue;
1607 }
1608 break text;
1609 };
1610 let body = if exp10 >= sig - 1 {
1611 format!("{digits}{}", "0".repeat((exp10 - sig + 1) as usize))
1612 } else if exp10 >= 0 {
1613 let (a, b) = digits.split_at((exp10 + 1) as usize);
1614 format!("{a}.{b}")
1615 } else {
1616 format!("0.{}{digits}", "0".repeat((-exp10 - 1) as usize))
1617 };
1618 Ok(if negative { format!("-{body}") } else { body })
1619 }
1620
1621 fn decimal_exponent(&self) -> Result<i64, RealError> {
1623 let ten = Self::from_i64(10);
1624 let mut power = Self::from_i64(1);
1625 let mut e = 0i64;
1626 if self.compare(&power, DEFAULT_BUDGET)? != Ordering::Less {
1627 loop {
1628 let next = power.mul(&ten);
1629 if self.compare(&next, DEFAULT_BUDGET)? == Ordering::Less {
1630 return Ok(e);
1631 }
1632 power = next;
1633 e += 1;
1634 }
1635 }
1636 let tenth = Self::from_rational(Rational::from_ratio_i64(1, 10).expect("10 ≠ 0"));
1637 loop {
1638 power = power.mul(&tenth);
1639 e -= 1;
1640 if self.compare(&power, DEFAULT_BUDGET)? != Ordering::Less {
1641 return Ok(e);
1642 }
1643 }
1644 }
1645
1646 pub fn truncated_decimal(&self, frac: u32) -> Result<String, RealError> {
1648 let negative = self.compare(&Self::from_i64(0), DEFAULT_BUDGET)? == Ordering::Less;
1649 let abs = if negative { self.neg() } else { self.clone() };
1650 let ten_k = Self::from_rational(Rational::from_bigint(BigInt::from_i64(10).pow(frac)));
1651 let digits_bits = (frac as f64 * std::f64::consts::LOG2_10).ceil() as u32;
1652 let n = abs.mul(&ten_k).floor(digits_bits + DEFAULT_BUDGET)?;
1653 let text = format!("{:0>width$}", n.to_string(), width = frac as usize + 1);
1654 let (int, fr) = text.split_at(text.len() - frac as usize);
1655 let sign = if negative { "-" } else { "" };
1656 Ok(if frac == 0 {
1657 format!("{sign}{int}")
1658 } else {
1659 format!("{sign}{int}.{fr}")
1660 })
1661 }
1662
1663 pub fn describe(&self) -> String {
1666 match &self.form {
1667 Form::General(n) => n.describe(),
1668 _ => self.to_string(),
1669 }
1670 }
1671}
1672
1673impl Node {
1674 fn is_transmissible(&self) -> bool {
1675 match self {
1676 Node::Alg(_) | Node::Pi => true,
1677 Node::Add(a, b) | Node::Mul(a, b) => a.is_transmissible() && b.is_transmissible(),
1678 Node::Neg(a)
1679 | Node::Recip(a)
1680 | Node::Exp(a)
1681 | Node::Log(a)
1682 | Node::Sin(a)
1683 | Node::Cos(a)
1684 | Node::Sqrt(a) => a.is_transmissible(),
1685 Node::Flow(solution, _) => solution.start.iter().all(ExactReal::is_transmissible),
1686 Node::Defined(_) => false,
1687 }
1688 }
1689
1690 fn describe(&self) -> String {
1691 let wrap = |x: &ExactReal| {
1692 let d = x.describe();
1693 if d.contains(' ') {
1694 format!("({d})")
1695 } else {
1696 d
1697 }
1698 };
1699 match self {
1700 Node::Alg(leaf) => leaf.value.to_string(),
1701 Node::Pi => "π".to_string(),
1702 Node::Add(a, b) => {
1703 if let Form::General(n) = &b.form {
1704 if let Node::Neg(inner) = n.as_ref() {
1705 return format!("{} - {}", a.describe(), wrap(inner));
1706 }
1707 }
1708 let bd = b.describe();
1709 match bd.strip_prefix('-') {
1710 Some(rest) if !rest.contains(' ') => format!("{} - {rest}", a.describe()),
1711 _ if bd.contains(' ') => format!("{} + ({bd})", a.describe()),
1712 _ => format!("{} + {bd}", a.describe()),
1713 }
1714 }
1715 Node::Mul(a, b) => format!("{}·{}", wrap(a), wrap(b)),
1716 Node::Neg(a) => format!("-{}", wrap(a)),
1717 Node::Recip(a) => format!("1/{}", wrap(a)),
1718 Node::Exp(a) => format!("exp({})", a.describe()),
1719 Node::Log(a) => format!("log({})", a.describe()),
1720 Node::Sin(a) => format!("sin({})", a.describe()),
1721 Node::Cos(a) => format!("cos({})", a.describe()),
1722 Node::Sqrt(a) => format!("√({})", a.describe()),
1723 Node::Flow(solution, i) => format!("x{} of a flow at time {}", i + 1, solution.t),
1724 Node::Defined(d) => d.describe(),
1725 }
1726 }
1727}
1728
1729fn coefficient_text(a: &Algebraic) -> String {
1734 let s = a.to_string();
1735 if s.contains(' ') || s.contains('/') {
1736 format!("({s})")
1737 } else {
1738 s
1739 }
1740}
1741
1742fn exponent_text(a: &Algebraic, base: &str) -> String {
1743 if *a == Algebraic::from_i64(1) {
1744 return base.to_string();
1745 }
1746 match a.to_rational() {
1747 Some(r) if r.is_integer() && !r.is_negative() => format!("{base}^{r}"),
1748 _ => format!("{base}^({a})"),
1749 }
1750}
1751
1752fn write_sum(f: &mut fmt::Formatter<'_>, terms: Vec<(bool, String)>) -> fmt::Result {
1754 for (i, (negative, body)) in terms.iter().enumerate() {
1755 match (i, negative) {
1756 (0, true) => write!(f, "-{body}")?,
1757 (0, false) => write!(f, "{body}")?,
1758 (_, true) => write!(f, " - {body}")?,
1759 (_, false) => write!(f, " + {body}")?,
1760 }
1761 }
1762 Ok(())
1763}
1764
1765fn product_text(coefficient: &Algebraic, factors: &[String]) -> (bool, String) {
1767 let negative = coefficient.signum() < 0;
1768 let magnitude = if negative { coefficient.neg() } else { coefficient.clone() };
1769 let mut parts: Vec<String> = Vec::new();
1770 if factors.is_empty() {
1771 return (negative, magnitude.to_string());
1772 }
1773 if magnitude != Algebraic::from_i64(1) {
1774 parts.push(coefficient_text(&magnitude));
1775 }
1776 parts.extend(factors.iter().cloned());
1777 (negative, parts.join("·"))
1778}
1779
1780impl fmt::Display for ExpSum {
1781 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1784 let two = Algebraic::from_i64(2);
1785 let mut terms = Vec::new();
1786 for (e, c) in &self.terms {
1787 if e.im.signum() < 0 {
1788 continue;
1789 }
1790 let mut factors = Vec::new();
1791 if !e.re.is_zero() {
1792 factors.push(exponent_text(&e.re, "e"));
1793 }
1794 if e.im.is_zero() {
1795 terms.push(product_text(&c.re, &factors));
1796 continue;
1797 }
1798 let cos_coef = c.re.mul(&two);
1799 let sin_coef = c.im.mul(&two).neg();
1800 if !cos_coef.is_zero() {
1801 let mut fs = factors.clone();
1802 fs.push(format!("cos({})", e.im));
1803 terms.push(product_text(&cos_coef, &fs));
1804 }
1805 if !sin_coef.is_zero() {
1806 let mut fs = factors;
1807 fs.push(format!("sin({})", e.im));
1808 terms.push(product_text(&sin_coef, &fs));
1809 }
1810 }
1811 write_sum(f, terms)
1812 }
1813}
1814
1815impl fmt::Display for PiPoly {
1816 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1817 let terms = self
1818 .terms
1819 .iter()
1820 .map(|(k, c)| {
1821 let factors = match k {
1822 0 => Vec::new(),
1823 1 => vec!["π".to_string()],
1824 k if *k > 1 => vec![format!("π^{k}")],
1825 k => vec![format!("π^({k})")],
1826 };
1827 product_text(c, &factors)
1828 })
1829 .collect();
1830 write_sum(f, terms)
1831 }
1832}
1833
1834impl fmt::Display for ExactReal {
1835 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1838 match &self.form {
1839 Form::Alg(a) => write!(f, "{a}"),
1840 Form::Exp(s) => write!(f, "{s}"),
1841 Form::Pi(p) => write!(f, "{p}"),
1842 Form::General(_) => write!(f, "{}", self.to_decimal(DISPLAY_DIGITS)),
1843 }
1844 }
1845}
1846
1847impl fmt::Debug for ExactReal {
1848 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1849 write!(f, "ExactReal({self})")
1850 }
1851}
1852
1853impl crate::exact_codec::ExactCodec for ExactReal {
1856 fn write(&self, out: &mut Vec<u8>) {
1862 use crate::exact_codec::write_len;
1863 match &self.form {
1864 Form::Alg(a) => {
1865 out.push(0);
1866 a.write(out);
1867 }
1868 Form::Exp(sum) => {
1869 out.push(1);
1870 write_len(sum.terms.len(), out);
1871 for (e, c) in &sum.terms {
1872 e.re.write(out);
1873 e.im.write(out);
1874 c.re.write(out);
1875 c.im.write(out);
1876 }
1877 }
1878 Form::Pi(poly) => {
1879 out.push(2);
1880 write_len(poly.terms.len(), out);
1881 for (k, c) in &poly.terms {
1882 (*k as i64).write(out);
1883 c.write(out);
1884 }
1885 }
1886 Form::General(node) => {
1887 out.push(3);
1888 let (tag, operands): (u8, Vec<&ExactReal>) = match node.as_ref() {
1889 Node::Add(a, b) => (0, vec![a, b]),
1890 Node::Mul(a, b) => (1, vec![a, b]),
1891 Node::Neg(a) => (2, vec![a]),
1892 Node::Recip(a) => (3, vec![a]),
1893 Node::Exp(a) => (4, vec![a]),
1894 Node::Log(a) => (5, vec![a]),
1895 Node::Sin(a) => (6, vec![a]),
1896 Node::Cos(a) => (7, vec![a]),
1897 Node::Sqrt(a) => (8, vec![a]),
1898 Node::Flow(solution, i) => {
1899 out.push(9);
1900 write_len(solution.field.components.len(), out);
1901 for monomials in &solution.field.components {
1902 write_len(monomials.len(), out);
1903 for m in monomials {
1904 m.coefficient.write(out);
1905 for e in &m.powers {
1906 u64::from(*e).write(out);
1907 }
1908 }
1909 }
1910 for x in &solution.start {
1911 x.write(out);
1912 }
1913 solution.t.write(out);
1914 write_len(*i, out);
1915 return;
1916 }
1917 Node::Defined(d) => {
1918 out.push(10);
1919 let description = d.describe();
1920 write_len(description.len(), out);
1921 out.extend_from_slice(description.as_bytes());
1922 return;
1923 }
1924 Node::Alg(_) | Node::Pi => {
1925 unreachable!("an algebraic or π leaf is an exact form, never a general real")
1926 }
1927 };
1928 out.push(tag);
1929 for x in operands {
1930 x.write(out);
1931 }
1932 }
1933 }
1934 }
1935
1936 fn read(buf: &[u8], pos: &mut usize) -> Option<Self> {
1937 read_real(buf, pos, 0)
1938 }
1939}
1940
1941fn read_real(buf: &[u8], pos: &mut usize, depth: usize) -> Option<ExactReal> {
1944 use crate::exact_codec::{read_byte, read_len, ExactCodec, MAX_WIRE_DEPTH, MAX_WIRE_LEN};
1945 if depth > MAX_WIRE_DEPTH {
1946 return None;
1947 }
1948 match read_byte(buf, pos)? {
1949 0 => Some(ExactReal::from_algebraic(Algebraic::read(buf, pos)?)),
1950 1 => {
1951 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
1952 let mut raw = Vec::with_capacity(n.min(64));
1953 for _ in 0..n {
1954 let e = Calg {
1955 re: Algebraic::read(buf, pos)?,
1956 im: Algebraic::read(buf, pos)?,
1957 };
1958 let c = Calg {
1959 re: Algebraic::read(buf, pos)?,
1960 im: Algebraic::read(buf, pos)?,
1961 };
1962 raw.push((e, c));
1963 }
1964 let sum = ExpSum::from_terms(raw);
1965 let conjugate = |z: &Calg| Calg {
1966 re: z.re.clone(),
1967 im: z.im.neg(),
1968 };
1969 let real = sum
1970 .terms
1971 .iter()
1972 .all(|(e, c)| sum.terms.iter().any(|(f, d)| *f == conjugate(e) && *d == conjugate(c)));
1973 real.then(|| ExactReal::of(Form::Exp(sum)))
1974 }
1975 2 => {
1976 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
1977 let mut raw = Vec::with_capacity(n.min(64));
1978 for _ in 0..n {
1979 let k = i32::try_from(i64::read(buf, pos)?).ok()?;
1980 raw.push((k, Algebraic::read(buf, pos)?));
1981 }
1982 Some(ExactReal::of(Form::Pi(PiPoly::from_terms(raw))))
1983 }
1984 3 => {
1985 let tag = read_byte(buf, pos)?;
1986 if tag == 9 {
1987 return read_flow(buf, pos, depth);
1988 }
1989 let a = read_real(buf, pos, depth + 1)?;
1990 match tag {
1991 0 => Some(a.add(&read_real(buf, pos, depth + 1)?)),
1992 1 => Some(a.mul(&read_real(buf, pos, depth + 1)?)),
1993 2 => Some(a.neg()),
1994 3 => a.recip().ok(),
1995 4 => Some(a.exp()),
1996 5 => a.log().ok(),
1997 6 => Some(a.sin()),
1998 7 => Some(a.cos()),
1999 8 => a.sqrt().ok(),
2000 _ => None,
2001 }
2002 }
2003 _ => None,
2004 }
2005}
2006
2007fn read_flow(buf: &[u8], pos: &mut usize, depth: usize) -> Option<ExactReal> {
2009 use crate::exact_codec::{read_len, ExactCodec, MAX_WIRE_LEN};
2010 use crate::ode::Monomial;
2011 let n = read_len(buf, pos, MAX_WIRE_LEN)?;
2012 let mut components = Vec::with_capacity(n.min(64));
2013 for _ in 0..n {
2014 let count = read_len(buf, pos, MAX_WIRE_LEN)?;
2015 let mut monomials = Vec::with_capacity(count.min(64));
2016 for _ in 0..count {
2017 let coefficient = Rational::read(buf, pos)?;
2018 let mut powers = Vec::with_capacity(n);
2019 for _ in 0..n {
2020 powers.push(u32::try_from(u64::read(buf, pos)?).ok()?);
2021 }
2022 monomials.push(Monomial { coefficient, powers });
2023 }
2024 components.push(monomials);
2025 }
2026 let mut start = Vec::with_capacity(n);
2027 for _ in 0..n {
2028 start.push(read_real(buf, pos, depth + 1)?);
2029 }
2030 let t = Rational::read(buf, pos)?;
2031 let i = read_len(buf, pos, n.saturating_sub(1))?;
2032 ExactReal::flow(&Field { components }, &start, &t)?.into_iter().nth(i)
2033}
2034
2035#[cfg(test)]
2036#[path = "../../logicaffeine_tests/unit/logicaffeine_base/exact_real/tests.rs"]
2037mod tests;