Skip to main content

zenith_float_num/
ext.rs

1//! ExactNum including finite numbers, NaN, and `Inf`.
2
3use crate::common::util::log2_ceil;
4use crate::defs::SignedWord;
5use crate::defs::DEFAULT_P;
6use crate::num::ExactNumNumber;
7use crate::Consts;
8use crate::Error;
9use crate::Exponent;
10use crate::Radix;
11use crate::RoundingMode;
12use crate::Sign;
13use crate::Word;
14use crate::WORD_BIT_SIZE;
15use core::num::FpCategory;
16use lazy_static::lazy_static;
17
18#[cfg(feature = "std")]
19use core::fmt::Write;
20
21#[cfg(not(feature = "std"))]
22use alloc::{string::String, vec::Vec};
23
24/// Not a number.
25pub const NAN: ExactNum = ExactNum {
26    inner: Flavor::NaN(None),
27};
28
29/// Positive infinity.
30pub const INF_POS: ExactNum = ExactNum {
31    inner: Flavor::Inf(Sign::Pos),
32};
33
34/// Negative infinity.
35pub const INF_NEG: ExactNum = ExactNum {
36    inner: Flavor::Inf(Sign::Neg),
37};
38
39lazy_static! {
40
41    /// 1
42    pub static ref ONE: ExactNum = ExactNum { inner: Flavor::Value(ExactNumNumber::from_word(1, DEFAULT_P).expect("Constant ONE initialized")) };
43
44    /// 2
45    pub static ref TWO: ExactNum = ExactNum { inner: Flavor::Value(ExactNumNumber::from_word(2, DEFAULT_P).expect("Constant TWO initialized")) };
46}
47
48/// A floating point number of arbitrary precision.
49#[derive(Debug)]
50pub struct ExactNum {
51    inner: Flavor,
52}
53
54#[derive(Debug)]
55enum Flavor {
56    Value(ExactNumNumber),
57    NaN(Option<Error>),
58    Inf(Sign), // signed Inf
59}
60
61impl ExactNum {
62    /// Returns a new number with value of 0 and precision of `p` bits. Precision is rounded upwards to the word size.
63    /// The function returns NaN if the precision `p` is incorrect.
64    pub fn new(p: usize) -> Self {
65        Self::result_to_ext(ExactNumNumber::new(p), false, true)
66    }
67
68    /// Constructs not-a-number with an associated error `err`.
69    pub fn nan(err: Option<Error>) -> Self {
70        ExactNum {
71            inner: Flavor::NaN(err),
72        }
73    }
74
75    /// Returns true if `self` is positive infinity.
76    pub fn is_inf_pos(&self) -> bool {
77        matches!(self.inner, Flavor::Inf(Sign::Pos))
78    }
79
80    /// Returns true if `self` is negative infinity.
81    pub fn is_inf_neg(&self) -> bool {
82        matches!(self.inner, Flavor::Inf(Sign::Neg))
83    }
84
85    /// Returns true if `self` is infinite.
86    pub fn is_inf(&self) -> bool {
87        matches!(self.inner, Flavor::Inf(_))
88    }
89
90    /// Return true if `self` is not a number.
91    pub fn is_nan(&self) -> bool {
92        matches!(self.inner, Flavor::NaN(_))
93    }
94
95    /// Return true if `self` is an integer number.
96    pub fn is_int(&self) -> bool {
97        match &self.inner {
98            Flavor::Value(v) => v.is_int(),
99            Flavor::NaN(_) => false,
100            Flavor::Inf(_) => false,
101        }
102    }
103
104    /// Returns the associated with NaN error, if any.
105    pub fn err(&self) -> Option<Error> {
106        match &self.inner {
107            Flavor::NaN(Some(e)) => Some(*e),
108            _ => None,
109        }
110    }
111
112    /// Adds `d2` to `self` and returns the result of the operation with precision `p` rounded according to `rm`.
113    /// Precision is rounded upwards to the word size.
114    /// The function returns NaN if the precision `p` is incorrect.
115    pub fn add(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
116        self.add_op(d2, p, rm, false)
117    }
118
119    /// Adds `d2` to `self` and returns the result of the operation.
120    /// The resulting precision is equal to the full precision of the result.
121    /// This operation can be used to emulate integer addition.
122    pub fn add_full_prec(&self, d2: &Self) -> Self {
123        self.add_op(d2, 0, RoundingMode::None, true)
124    }
125
126    fn add_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
127        match &self.inner {
128            Flavor::Value(v1) => match &d2.inner {
129                Flavor::Value(v2) => Self::result_to_ext(
130                    if full_prec { v1.add_full_prec(v2) } else { v1.add(v2, p, rm) },
131                    v1.is_zero(),
132                    v1.sign() == v2.sign(),
133                ),
134                Flavor::Inf(s2) => ExactNum {
135                    inner: Flavor::Inf(*s2),
136                },
137                Flavor::NaN(err) => Self::nan(*err),
138            },
139            Flavor::Inf(s1) => match &d2.inner {
140                Flavor::Value(_) => ExactNum {
141                    inner: Flavor::Inf(*s1),
142                },
143                Flavor::Inf(s2) => {
144                    if *s1 != *s2 {
145                        NAN
146                    } else {
147                        ExactNum {
148                            inner: Flavor::Inf(*s2),
149                        }
150                    }
151                }
152                Flavor::NaN(err) => Self::nan(*err),
153            },
154            Flavor::NaN(err) => Self::nan(*err),
155        }
156    }
157
158    /// Subtracts `d2` from `self` and returns the result of the operation with precision `p` rounded according to `rm`.
159    /// Precision is rounded upwards to the word size.
160    /// The function returns NaN if the precision `p` is incorrect.
161    pub fn sub(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
162        self.sub_op(d2, p, rm, false)
163    }
164
165    /// Subtracts `d2` from `self` and returns the result of the operation.
166    /// The resulting precision is equal to the full precision of the result.
167    /// This operation can be used to emulate integer subtraction.
168    pub fn sub_full_prec(&self, d2: &Self) -> Self {
169        self.sub_op(d2, 0, RoundingMode::None, true)
170    }
171
172    fn sub_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
173        match &self.inner {
174            Flavor::Value(v1) => match &d2.inner {
175                Flavor::Value(v2) => Self::result_to_ext(
176                    if full_prec { v1.sub_full_prec(v2) } else { v1.sub(v2, p, rm) },
177                    v1.is_zero(),
178                    v1.sign() == v2.sign(),
179                ),
180                Flavor::Inf(s2) => {
181                    if s2.is_positive() {
182                        INF_NEG
183                    } else {
184                        INF_POS
185                    }
186                }
187                Flavor::NaN(err) => Self::nan(*err),
188            },
189            Flavor::Inf(s1) => match &d2.inner {
190                Flavor::Value(_) => ExactNum {
191                    inner: Flavor::Inf(*s1),
192                },
193                Flavor::Inf(s2) => {
194                    if *s1 == *s2 {
195                        NAN
196                    } else {
197                        ExactNum {
198                            inner: Flavor::Inf(*s1),
199                        }
200                    }
201                }
202                Flavor::NaN(err) => Self::nan(*err),
203            },
204            Flavor::NaN(err) => Self::nan(*err),
205        }
206    }
207
208    /// Multiplies `d2` by `self` and returns the result of the operation with precision `p` rounded according to `rm`.
209    /// Precision is rounded upwards to the word size.
210    /// The function returns NaN if the precision `p` is incorrect.
211    pub fn mul(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
212        self.mul_op(d2, p, rm, false)
213    }
214
215    /// Multiplies `d2` by `self` and returns the result of the operation.
216    /// The resulting precision is equal to the full precision of the result.
217    /// This operation can be used to emulate integer multiplication.
218    pub fn mul_full_prec(&self, d2: &Self) -> Self {
219        self.mul_op(d2, 0, RoundingMode::None, true)
220    }
221
222    /// Computes `self * b + c` with precision `p`, rounded once with `rm`.
223    ///
224    /// Unlike `mul` followed by `add`, the product is not rounded to `p` before the addition.
225    pub fn fma(&self, b: &Self, c: &Self, p: usize, rm: RoundingMode) -> Self {
226        if self.is_nan() {
227            return self.clone();
228        }
229        if b.is_nan() {
230            return b.clone();
231        }
232        if c.is_nan() {
233            return c.clone();
234        }
235        match (&self.inner, &b.inner, &c.inner) {
236            (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv)) => {
237                Self::result_to_ext(a.fma(bv, cv, p, rm), false, true)
238            }
239            _ => {
240                let prod = self.mul(b, p, RoundingMode::None);
241                prod.add(c, p, rm)
242            }
243        }
244    }
245
246    /// Knuth–Dekker two-sum: `(hi, lo)` with `hi` rounded to `p` bits using `rm` and
247    /// `hi + lo` equal to the exact sum of finite operands (via [`add_full_prec`](Self::add_full_prec)).
248    /// Unlike a hardware-float Dekker two-sum, this takes `(p, rm)` because the high part is an
249    /// `ExactNum` at a chosen precision, not an implicit machine word.
250    ///
251    /// Inf / NaN: `hi` is `self.add(b, p, rm)`; `lo` is zero (or NaN if `hi` is NaN).
252    /// Reconstruct with `hi.add(&lo, p, rm)` (not `add_full_prec`, which uses internal precision 0).
253    pub fn two_sum(&self, b: &Self, p: usize, rm: RoundingMode) -> (Self, Self) {
254        if self.is_nan() {
255            return (self.clone(), Self::nan(self.err()));
256        }
257        if b.is_nan() {
258            return (b.clone(), Self::nan(b.err()));
259        }
260        if self.is_inf() || b.is_inf() {
261            return (self.add(b, p, rm), Self::new(p));
262        }
263        let exact = self.add_full_prec(b);
264        let mut hi = exact.clone();
265        if let Err(err) = hi.set_precision(p, rm) {
266            return (Self::nan(Some(err)), Self::nan(Some(err)));
267        }
268        let lo = exact.sub_full_prec(&hi);
269        (hi, Self::normalize_eft_lo(lo, p))
270    }
271
272    fn normalize_eft_lo(lo: Self, p: usize) -> Self {
273        if lo.is_nan() {
274            return lo;
275        }
276        if lo.is_zero() {
277            let mut z = Self::new(p);
278            z.set_inexact(lo.inexact());
279            return z;
280        }
281        lo
282    }
283
284    /// Two-product: `(hi, lo)` with `hi` rounded to `p` bits using `rm` and `hi + lo` equal to the
285    /// exact product of finite operands (via [`mul_full_prec`](Self::mul_full_prec)).
286    pub fn two_product(&self, b: &Self, p: usize, rm: RoundingMode) -> (Self, Self) {
287        if self.is_nan() {
288            return (self.clone(), Self::nan(self.err()));
289        }
290        if b.is_nan() {
291            return (b.clone(), Self::nan(b.err()));
292        }
293        if self.is_inf() || b.is_inf() {
294            return (self.mul(b, p, rm), Self::new(p));
295        }
296        let exact = self.mul_full_prec(b);
297        let mut hi = exact.clone();
298        if let Err(err) = hi.set_precision(p, rm) {
299            return (Self::nan(Some(err)), Self::nan(Some(err)));
300        }
301        let lo = exact.sub_full_prec(&hi);
302        (hi, Self::normalize_eft_lo(lo, p))
303    }
304
305    /// Sum `xs` at extra working precision and round once to `p` bits.
306    pub fn fused_sum(xs: &[Self], p: usize, rm: RoundingMode) -> Self {
307        if xs.is_empty() {
308            return Self::new(p);
309        }
310        let extra = log2_ceil(xs.len().max(1)).saturating_add(2);
311        let p_wrk = match p
312            .checked_add(WORD_BIT_SIZE)
313            .and_then(|v| v.checked_add(extra))
314        {
315            Some(v) => v,
316            None => return Self::nan(Some(Error::InvalidArgument)),
317        };
318        let mut acc = Self::new(p_wrk);
319        for x in xs {
320            acc = acc.add(x, p_wrk, RoundingMode::None);
321        }
322        if let Err(err) = acc.set_precision(p, rm) {
323            return Self::nan(Some(err));
324        }
325        acc
326    }
327
328    /// Dot product of equal-length slices: extra-precision `∑ xs[i]*ys[i]`, then one round to `p`.
329    /// Length mismatch yields NaN (`InvalidArgument`).
330    pub fn fused_dot(xs: &[Self], ys: &[Self], p: usize, rm: RoundingMode) -> Self {
331        if xs.len() != ys.len() {
332            return Self::nan(Some(Error::InvalidArgument));
333        }
334        if xs.is_empty() {
335            return Self::new(p);
336        }
337        let extra = log2_ceil(xs.len().max(1)).saturating_add(2);
338        let p_wrk = match p
339            .checked_add(WORD_BIT_SIZE)
340            .and_then(|v| v.checked_add(extra))
341        {
342            Some(v) => v,
343            None => return Self::nan(Some(Error::InvalidArgument)),
344        };
345        let mut acc = Self::new(p_wrk);
346        for (x, y) in xs.iter().zip(ys.iter()) {
347            let prod = x.mul(y, p_wrk, RoundingMode::None);
348            acc = acc.add(&prod, p_wrk, RoundingMode::None);
349        }
350        if let Err(err) = acc.set_precision(p, rm) {
351            return Self::nan(Some(err));
352        }
353        acc
354    }
355
356    /// Horner evaluation `a₀ + x(a₁ + x(a₂ + …))` with fused multiply-add at extra working precision,
357    /// then one round to `p`. `coeffs[0]` is the constant term (lowest degree first).
358    /// Empty `coeffs` yields zero.
359    pub fn polyval(coeffs: &[Self], x: &Self, p: usize, rm: RoundingMode) -> Self {
360        if coeffs.is_empty() {
361            return Self::new(p);
362        }
363        let extra = log2_ceil(coeffs.len().max(1)).saturating_add(2);
364        let p_wrk = match p
365            .checked_add(WORD_BIT_SIZE)
366            .and_then(|v| v.checked_add(extra))
367        {
368            Some(v) => v,
369            None => return Self::nan(Some(Error::InvalidArgument)),
370        };
371        let mut acc = coeffs[coeffs.len() - 1].clone();
372        if let Err(err) = acc.set_precision(p_wrk, RoundingMode::None) {
373            return Self::nan(Some(err));
374        }
375        for a in coeffs.iter().rev().skip(1) {
376            acc = acc.fma(x, a, p_wrk, RoundingMode::None);
377        }
378        if let Err(err) = acc.set_precision(p, rm) {
379            return Self::nan(Some(err));
380        }
381        acc
382    }
383
384    /// Alias of [`Self::fma`].
385    pub fn mul_add(&self, b: &Self, c: &Self, p: usize, rm: RoundingMode) -> Self {
386        if self.is_nan() {
387            return self.clone();
388        }
389        if b.is_nan() {
390            return b.clone();
391        }
392        if c.is_nan() {
393            return c.clone();
394        }
395        match (&self.inner, &b.inner, &c.inner) {
396            (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv)) => {
397                Self::result_to_ext(a.mul_add(bv, cv, p, rm), false, true)
398            }
399            _ => self.fma(b, c, p, rm),
400        }
401    }
402
403    fn mul_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
404        match &self.inner {
405            Flavor::Value(v1) => {
406                match &d2.inner {
407                    Flavor::Value(v2) => Self::result_to_ext(
408                        if full_prec { v1.mul_full_prec(v2) } else { v1.mul(v2, p, rm) },
409                        v1.is_zero(),
410                        v1.sign() == v2.sign(),
411                    ),
412                    Flavor::Inf(s2) => {
413                        if v1.is_zero() {
414                            // 0*inf
415                            NAN
416                        } else {
417                            let s = if v1.sign() == *s2 { Sign::Pos } else { Sign::Neg };
418                            ExactNum {
419                                inner: Flavor::Inf(s),
420                            }
421                        }
422                    }
423                    Flavor::NaN(err) => Self::nan(*err),
424                }
425            }
426            Flavor::Inf(s1) => {
427                match &d2.inner {
428                    Flavor::Value(v2) => {
429                        if v2.is_zero() {
430                            // inf*0
431                            NAN
432                        } else {
433                            let s = if v2.sign() == *s1 { Sign::Pos } else { Sign::Neg };
434                            ExactNum {
435                                inner: Flavor::Inf(s),
436                            }
437                        }
438                    }
439                    Flavor::Inf(s2) => {
440                        let s = if s1 == s2 { Sign::Pos } else { Sign::Neg };
441                        ExactNum {
442                            inner: Flavor::Inf(s),
443                        }
444                    }
445                    Flavor::NaN(err) => Self::nan(*err),
446                }
447            }
448            Flavor::NaN(err) => Self::nan(*err),
449        }
450    }
451
452    /// Divides `self` by `d2` and returns the result of the operation with precision `p` rounded according to `rm`.
453    /// Precision is rounded upwards to the word size.
454    /// The function returns NaN if the precision `p` is incorrect.
455    pub fn div(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
456        match &self.inner {
457            Flavor::Value(v1) => match &d2.inner {
458                Flavor::Value(v2) => {
459                    Self::result_to_ext(v1.div(v2, p, rm), v1.is_zero(), v1.sign() == v2.sign())
460                }
461                Flavor::Inf(_) => Self::new(v1.mantissa_max_bit_len()),
462                Flavor::NaN(err) => Self::nan(*err),
463            },
464            Flavor::Inf(s1) => match &d2.inner {
465                Flavor::Value(v) => {
466                    if *s1 == v.sign() {
467                        INF_POS
468                    } else {
469                        INF_NEG
470                    }
471                }
472                Flavor::Inf(_) => NAN,
473                Flavor::NaN(err) => Self::nan(*err),
474            },
475            Flavor::NaN(err) => Self::nan(*err),
476        }
477    }
478
479    /// Returns the remainder of division of `|self|` by `|d2|`. The sign of the result is set to the sign of `self`.
480    pub fn rem(&self, d2: &Self) -> Self {
481        match &self.inner {
482            Flavor::Value(v1) => match &d2.inner {
483                Flavor::Value(v2) => {
484                    Self::result_to_ext(v1.rem(v2), v1.is_zero(), v1.sign() == v2.sign())
485                }
486                Flavor::Inf(_) => self.clone(),
487                Flavor::NaN(err) => Self::nan(*err),
488            },
489            Flavor::Inf(_) => NAN,
490            Flavor::NaN(err) => Self::nan(*err),
491        }
492    }
493
494    /// Compares `self` to `d2`.
495    /// Returns positive if `self` > `d2`, negative if `self` < `d2`, zero if `self` == `d2`, None if `self` or `d2` is NaN.
496    #[allow(clippy::should_implement_trait)]
497    pub fn cmp(&self, d2: &ExactNum) -> Option<SignedWord> {
498        match &self.inner {
499            Flavor::Value(v1) => match &d2.inner {
500                Flavor::Value(v2) => Some(v1.cmp(v2)),
501                Flavor::Inf(s2) => {
502                    if *s2 == Sign::Pos {
503                        Some(-1)
504                    } else {
505                        Some(1)
506                    }
507                }
508                Flavor::NaN(_) => None,
509            },
510            Flavor::Inf(s1) => match &d2.inner {
511                Flavor::Value(_) => Some(*s1 as SignedWord),
512                Flavor::Inf(s2) => Some(*s1 as SignedWord - *s2 as SignedWord),
513                Flavor::NaN(_) => None,
514            },
515            Flavor::NaN(_) => None,
516        }
517    }
518
519    /// Compares the absolute value of `self` to the absolute value of `d2`.
520    /// Returns positive if `|self|` is greater than `|d2|`, negative if `|self|` is smaller than `|d2|`, 0 if `|self|` equals to `|d2|`, None if `self` or `d2` is NaN.
521    pub fn abs_cmp(&self, d2: &Self) -> Option<SignedWord> {
522        match &self.inner {
523            Flavor::Value(v1) => match &d2.inner {
524                Flavor::Value(v2) => Some(v1.cmp(v2)),
525                Flavor::Inf(_) => Some(-1),
526                Flavor::NaN(_) => None,
527            },
528            Flavor::Inf(_) => match &d2.inner {
529                Flavor::Value(_) => Some(1),
530                Flavor::Inf(_) => Some(0),
531                Flavor::NaN(_) => None,
532            },
533            Flavor::NaN(_) => None,
534        }
535    }
536
537    /// Reverses the sign of `self`.
538    pub fn inv_sign(&mut self) {
539        match &mut self.inner {
540            Flavor::Value(v1) => v1.inv_sign(),
541            Flavor::Inf(s) => self.inner = Flavor::Inf(s.invert()),
542            Flavor::NaN(_) => {}
543        }
544    }
545
546    /// Compute the power of `self` to the `n` with precision `p`. The result is rounded using the rounding mode `rm`.
547    /// This function requires constants cache `cc` for computing the result.
548    /// Precision is rounded upwards to the word size.
549    /// The function returns NaN if the precision `p` is incorrect.
550    pub fn pow(&self, n: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
551        match &self.inner {
552            Flavor::Value(v1) => {
553                match &n.inner {
554                    Flavor::Value(v2) => Self::result_to_ext(
555                        v1.pow(v2, p, rm, cc),
556                        v1.is_zero(),
557                        v1.sign() == v2.sign(),
558                    ),
559                    Flavor::Inf(s2) => {
560                        // v1^inf
561                        let val = v1.cmp(&crate::common::consts::ONE);
562                        if val > 0 {
563                            ExactNum {
564                                inner: Flavor::Inf(*s2),
565                            }
566                        } else if val < 0 {
567                            Self::new(p)
568                        } else {
569                            Self::from_u8(1, p)
570                        }
571                    }
572                    Flavor::NaN(err) => Self::nan(*err),
573                }
574            }
575            Flavor::Inf(s1) => {
576                match &n.inner {
577                    Flavor::Value(v2) => {
578                        // inf ^ v2
579                        if v2.is_zero() {
580                            Self::from_u8(1, p)
581                        } else if v2.is_positive() {
582                            if s1.is_negative() && v2.is_odd_int() {
583                                // v2 is odd and has no fractional part.
584                                INF_NEG
585                            } else {
586                                INF_POS
587                            }
588                        } else {
589                            Self::new(p)
590                        }
591                    }
592                    Flavor::Inf(s2) => {
593                        // inf^inf
594                        if s2.is_positive() {
595                            INF_POS
596                        } else {
597                            Self::new(p)
598                        }
599                    }
600                    Flavor::NaN(err) => Self::nan(*err),
601                }
602            }
603            Flavor::NaN(err) => Self::nan(*err),
604        }
605    }
606
607    /// Compute the power of `self` to the integer `n` with precision `p`. The result is rounded using the rounding mode `rm`.
608    /// Precision is rounded upwards to the word size.
609    /// The function returns NaN if the precision `p` is incorrect.
610    pub fn powi(&self, n: usize, p: usize, rm: RoundingMode) -> Self {
611        match &self.inner {
612            Flavor::Value(v1) => Self::result_to_ext(v1.powi(n, p, rm), false, true),
613            Flavor::Inf(s1) => {
614                // inf ^ v2
615                if n == 0 {
616                    Self::from_u8(1, p)
617                } else if s1.is_negative() && (n & 1 == 1) {
618                    INF_NEG
619                } else {
620                    INF_POS
621                }
622            }
623            Flavor::NaN(err) => Self::nan(*err),
624        }
625    }
626
627    /// Compute the power of `self` to the signed integer `n` with precision `p`. The result is rounded using the rounding mode `rm`.
628    /// Precision is rounded upwards to the word size.
629    /// Negative `n` is a reciprocal of the corresponding positive power.
630    /// The function returns NaN if the precision `p` is incorrect, or Inf if `self` is zero and `n` is negative.
631    pub fn powsi(&self, n: isize, p: usize, rm: RoundingMode) -> Self {
632        match &self.inner {
633            Flavor::Value(v1) => Self::result_to_ext(v1.powsi(n, p, rm), false, true),
634            Flavor::Inf(s1) => {
635                if n == 0 {
636                    Self::from_u8(1, p)
637                } else if n < 0 {
638                    Self::new(p)
639                } else if s1.is_negative() && (n & 1 == 1) {
640                    INF_NEG
641                } else {
642                    INF_POS
643                }
644            }
645            Flavor::NaN(err) => Self::nan(*err),
646        }
647    }
648
649    /// Computes the logarithm base `n` of a number with precision `p`. The result is rounded using the rounding mode `rm`.
650    /// This function requires constants cache `cc` for computing the result.
651    /// Precision is rounded upwards to the word size.
652    /// The function returns NaN if the precision `p` is incorrect.
653    pub fn log(&self, n: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
654        match &self.inner {
655            Flavor::Value(v1) => {
656                match &n.inner {
657                    Flavor::Value(v2) => {
658                        if v2.is_zero() {
659                            return INF_NEG;
660                        }
661                        Self::result_to_ext(v1.log(v2, p, rm, cc), false, true)
662                    }
663                    Flavor::Inf(s2) => {
664                        // v1.log(inf)
665                        if s2.is_positive() {
666                            Self::new(p)
667                        } else {
668                            NAN
669                        }
670                    }
671                    Flavor::NaN(err) => Self::nan(*err),
672                }
673            }
674            Flavor::Inf(s1) => {
675                if *s1 == Sign::Neg {
676                    // -inf.log(any)
677                    NAN
678                } else {
679                    match &n.inner {
680                        Flavor::Value(v2) => {
681                            // +inf.log(v2)
682                            if v2.exponent() <= 0 {
683                                INF_NEG
684                            } else {
685                                INF_POS
686                            }
687                        }
688                        Flavor::Inf(_) => NAN, // +inf.log(inf)
689                        Flavor::NaN(err) => Self::nan(*err),
690                    }
691                }
692            }
693            Flavor::NaN(err) => Self::nan(*err),
694        }
695    }
696
697    /// Returns true if `self` is positive.
698    /// The function returns false if `self` is NaN.
699    pub fn is_positive(&self) -> bool {
700        match &self.inner {
701            Flavor::Value(v) => v.is_positive(),
702            Flavor::Inf(s) => *s == Sign::Pos,
703            Flavor::NaN(_) => false,
704        }
705    }
706
707    /// Returns true if `self` is negative.
708    /// The function returns false if `self` is NaN.
709    pub fn is_negative(&self) -> bool {
710        match &self.inner {
711            Flavor::Value(v) => v.is_negative(),
712            Flavor::Inf(s) => *s == Sign::Neg,
713            Flavor::NaN(_) => false,
714        }
715    }
716
717    /// Returns true if `self` is subnormal. A number is subnormal if the most significant bit of the mantissa is not equal to 1.
718    pub fn is_subnormal(&self) -> bool {
719        if let Flavor::Value(v) = &self.inner {
720            return v.is_subnormal();
721        }
722        false
723    }
724
725    /// Returns true if `self` is zero.
726    pub fn is_zero(&self) -> bool {
727        match &self.inner {
728            Flavor::Value(v) => v.is_zero(),
729            Flavor::Inf(_) => false,
730            Flavor::NaN(_) => false,
731        }
732    }
733
734    /// Restricts the value of `self` to an interval determined by the values of `min` and `max`.
735    /// The function returns `max` if `self` is greater than `max`, `min` if `self` is less than `min`, and `self` otherwise.
736    /// If either argument is NaN or `min` is greater than `max`, the function returns NaN.
737    pub fn clamp(&self, min: &Self, max: &Self) -> Self {
738        if self.is_nan() || min.is_nan() || max.is_nan() || max.cmp(min).unwrap() < 0 {
739            // call to unwrap() is unreacheable
740            NAN
741        } else if self.cmp(min).unwrap() < 0 {
742            // call to unwrap() is unreacheable
743            min.clone()
744        } else if self.cmp(max).unwrap() > 0 {
745            // call to unwrap() is unreacheable
746            max.clone()
747        } else {
748            self.clone()
749        }
750    }
751
752    /// Returns the value of `d1` if `d1` is greater than `self`, or the value of `self` otherwise.
753    /// If either argument is NaN, the function returns NaN.
754    pub fn max(&self, d1: &Self) -> Self {
755        if self.is_nan() || d1.is_nan() {
756            NAN
757        } else if self.cmp(d1).unwrap() < 0 {
758            // call to unwrap() is unreacheable
759            d1.clone()
760        } else {
761            self.clone()
762        }
763    }
764
765    /// Returns value of `d1` if `d1` is less than `self`, or the value of `self` otherwise.
766    /// If either argument is NaN, the function returns NaN.
767    pub fn min(&self, d1: &Self) -> Self {
768        if self.is_nan() || d1.is_nan() {
769            NAN
770        } else if self.cmp(d1).unwrap() > 0 {
771            // call to unwrap() is unreacheable
772            d1.clone()
773        } else {
774            self.clone()
775        }
776    }
777
778    /// Returns a ExactNum with the value -1 if `self` is negative, 1 if `self` is positive, zero otherwise.
779    /// The function returns NaN If `self` is NaN.
780    pub fn signum(&self) -> Self {
781        if self.is_nan() {
782            NAN
783        } else if self.is_negative() {
784            let mut ret = Self::from_u8(1, DEFAULT_P);
785            ret.inv_sign();
786            ret
787        } else {
788            Self::from_u8(1, DEFAULT_P)
789        }
790    }
791
792    /// Parses a number from the string `s`.
793    /// The function expects `s` to be a number in scientific format in radix `rdx`, or +-Inf, or NaN.
794    /// if `p` equals to usize::MAX then the precision of the resulting number is determined automatically from the input.
795    ///
796    /// ## Examples
797    ///
798    /// ```
799    /// # use zenith_float_num::ExactNum;
800    /// # use zenith_float_num::Radix;
801    /// # use zenith_float_num::RoundingMode;
802    /// # use zenith_float_num::Consts;
803    /// let mut cc = Consts::new().expect("Constants cache initialized.");
804    ///
805    /// let n = ExactNum::parse("0.0", Radix::Bin, 64, RoundingMode::ToEven, &mut cc);
806    /// assert!(n.is_zero());
807    ///
808    /// let n = ExactNum::parse("-Inf", Radix::Hex, 1, RoundingMode::None, &mut cc);
809    /// assert!(n.is_inf_neg());
810    ///
811    /// let n = ExactNum::parse("NaN", Radix::Oct, 2, RoundingMode::None, &mut cc);
812    /// assert!(n.is_nan());
813    /// ```
814    pub fn parse(s: &str, rdx: Radix, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
815        match crate::parser::parse(s, rdx) {
816            Ok(ps) => {
817                if ps.is_inf() {
818                    if ps.sign() == Sign::Pos {
819                        INF_POS
820                    } else {
821                        INF_NEG
822                    }
823                } else if ps.is_nan() {
824                    NAN
825                } else {
826                    let (m, s, e) = ps.raw_parts();
827                    Self::result_to_ext(
828                        ExactNumNumber::convert_from_radix(s, m, e, rdx, p, rm, cc),
829                        false,
830                        true,
831                    )
832                }
833            }
834            Err(e) => Self::nan(Some(e)),
835        }
836    }
837
838    #[cfg(feature = "std")]
839    pub(crate) fn write_str<T: Write>(
840        &self,
841        w: &mut T,
842        rdx: Radix,
843        rm: RoundingMode,
844        cc: &mut Consts,
845    ) -> Result<(), core::fmt::Error> {
846        match &self.inner {
847            Flavor::Value(v) => match v.format(rdx, rm, cc) {
848                Ok(s) => w.write_str(&s),
849                Err(e) => match e {
850                    Error::ExponentOverflow(s) => {
851                        if s.is_positive() {
852                            w.write_str("Inf")
853                        } else {
854                            w.write_str("-Inf")
855                        }
856                    }
857                    _ => w.write_str("Err"),
858                },
859            },
860            Flavor::Inf(sign) => {
861                let s = if sign.is_negative() { "-Inf" } else { "Inf" };
862                w.write_str(s)
863            }
864            crate::ext::Flavor::NaN(_) => w.write_str("NaN"),
865        }
866    }
867
868    /// Formats the number using radix `rdx` and rounding mode `rm`.
869    /// Note, since hexadecimal digits include the character "e", the exponent part is separated
870    /// from the mantissa by "_".
871    /// For example, a number with mantissa `123abcdef` and exponent `123` would be formatted as `123abcdef_e+123`.
872    ///
873    /// ## Errors
874    ///
875    ///  - MemoryAllocation: failed to allocate memory for mantissa.
876    ///  - ExponentOverflow: the resulting exponent becomes greater than the maximum allowed value for the exponent.
877    pub fn format(&self, rdx: Radix, rm: RoundingMode, cc: &mut Consts) -> Result<String, Error> {
878        let s = match &self.inner {
879            Flavor::Value(v) => match v.format(rdx, rm, cc) {
880                Ok(s) => return Ok(s),
881                Err(e) => match e {
882                    Error::ExponentOverflow(s) => {
883                        if s.is_positive() {
884                            "Inf"
885                        } else {
886                            "-Inf"
887                        }
888                    }
889                    _ => "Err",
890                },
891            },
892            Flavor::Inf(sign) => {
893                if sign.is_negative() {
894                    "-Inf"
895                } else {
896                    "Inf"
897                }
898            }
899            crate::ext::Flavor::NaN(_) => "NaN",
900        };
901
902        let mut ret = String::new();
903        ret.try_reserve_exact(s.len())?;
904        ret.push_str(s);
905
906        Ok(ret)
907    }
908
909    /// Wraps `self` in a [`crate::RadixFloat`] tagged with `radix` for parse/format.
910    pub fn with_radix(self, radix: Radix) -> crate::radix_float::RadixFloat {
911        crate::radix_float::RadixFloat::with_radix(self, radix)
912    }
913
914    /// Returns a random normalized (not subnormal) ExactNum number with exponent in the range
915    /// from `exp_from` to `exp_to` inclusive. The sign can be positive and negative. Zero is excluded.
916    /// Precision is rounded upwards to the word size.
917    /// Function does not follow any specific distribution law.
918    /// The intended use of this function is for testing.
919    /// The function returns NaN if the precision `p` is incorrect or when `exp_from` is less than EXPONENT_MIN or `exp_to` is greater than EXPONENT_MAX.
920    #[cfg(feature = "random")]
921    pub fn random_normal(p: usize, exp_from: Exponent, exp_to: Exponent) -> Self {
922        Self::result_to_ext(
923            ExactNumNumber::random_normal(p, exp_from, exp_to),
924            false,
925            true,
926        )
927    }
928
929    /// Returns category of `self`.
930    pub fn classify(&self) -> FpCategory {
931        match &self.inner {
932            Flavor::Value(v) => {
933                if v.is_subnormal() {
934                    FpCategory::Subnormal
935                } else if v.is_zero() {
936                    FpCategory::Zero
937                } else {
938                    FpCategory::Normal
939                }
940            }
941            Flavor::Inf(_) => FpCategory::Infinite,
942            Flavor::NaN(_) => FpCategory::Nan,
943        }
944    }
945
946    /// Computes the arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
947    /// This function requires constants cache `cc` for computing the result.
948    /// Precision is rounded upwards to the word size.
949    /// The function returns NaN if the precision `p` is incorrect.
950    pub fn atan(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
951        match &self.inner {
952            Flavor::Value(v) => Self::result_to_ext(v.atan(p, rm, cc), v.is_zero(), true),
953            Flavor::Inf(s) => Self::result_to_ext(Self::half_pi(*s, p, rm, cc), false, true),
954            Flavor::NaN(err) => Self::nan(*err),
955        }
956    }
957
958    /// Computes `atan2(self, x)` with precision `p` (quadrant-aware arctangent of `self / x`).
959    /// The result is rounded using the rounding mode `rm`.
960    /// This function requires constants cache `cc`.
961    /// Precision is rounded upwards to the word size.
962    pub fn atan2(&self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
963        if self.is_nan() {
964            return self.clone();
965        }
966        if x.is_nan() {
967            return x.clone();
968        }
969
970        match (&self.inner, &x.inner) {
971            (Flavor::Inf(sy), Flavor::Inf(sx)) => {
972                let mut q = cc.pi(p, rm);
973                q = q.div(&ExactNum::from_word(4, p), p, rm);
974                if sx.is_negative() {
975                    let three = ExactNum::from_word(3, p);
976                    q = three.mul(&q, p, rm);
977                }
978                if sy.is_negative() {
979                    q.neg()
980                } else {
981                    q
982                }
983            }
984            (Flavor::Inf(sy), Flavor::Value(_)) => {
985                Self::result_to_ext(Self::half_pi(*sy, p, rm, cc), false, true)
986            }
987            (Flavor::Value(y), Flavor::Inf(sx)) => {
988                if sx.is_positive() {
989                    Self::result_to_ext(ExactNumNumber::new2(p, y.sign(), y.inexact()), false, true)
990                } else {
991                    let mut pi = cc.pi(p, rm);
992                    pi.set_sign(y.sign());
993                    pi
994                }
995            }
996            (Flavor::Value(y), Flavor::Value(xv)) => {
997                Self::result_to_ext(y.atan2(xv, p, rm, cc), false, false)
998            }
999            _ => NAN,
1000        }
1001    }
1002
1003    /// Computes `sqrt(self² + other²)` with precision `p`.
1004    /// The result is rounded using the rounding mode `rm`.
1005    /// Precision is rounded upwards to the word size.
1006    /// `hypot(±Inf, y)` and `hypot(x, ±Inf)` are `+Inf`, including when the other argument is NaN.
1007    pub fn hypot(&self, other: &Self, p: usize, rm: RoundingMode) -> Self {
1008        if self.is_inf() || other.is_inf() {
1009            return INF_POS;
1010        }
1011        if self.is_nan() {
1012            return self.clone();
1013        }
1014        if other.is_nan() {
1015            return other.clone();
1016        }
1017        match (&self.inner, &other.inner) {
1018            (Flavor::Value(a), Flavor::Value(b)) => {
1019                Self::result_to_ext(a.hypot(b, p, rm), false, true)
1020            }
1021            _ => NAN,
1022        }
1023    }
1024
1025    /// Computes `ln(1 + self)` with precision `p`.
1026    /// The result is rounded using the rounding mode `rm`.
1027    /// This function requires constants cache `cc`.
1028    /// Returns `-Inf` for `self == -1`, and NaN if `self < -1`.
1029    pub fn log1p(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1030        match &self.inner {
1031            Flavor::Value(v) => Self::result_to_ext(v.log1p(p, rm, cc), false, false),
1032            Flavor::Inf(s) => {
1033                if s.is_positive() {
1034                    INF_POS
1035                } else {
1036                    NAN
1037                }
1038            }
1039            Flavor::NaN(err) => Self::nan(*err),
1040        }
1041    }
1042
1043    /// Computes `exp(self) - 1` with precision `p`.
1044    /// The result is rounded using the rounding mode `rm`.
1045    /// This function requires constants cache `cc`.
1046    pub fn expm1(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1047        match &self.inner {
1048            Flavor::Value(v) => Self::result_to_ext(v.expm1(p, rm, cc), false, true),
1049            Flavor::Inf(s) => {
1050                if s.is_positive() {
1051                    INF_POS
1052                } else {
1053                    ExactNum::from_i8(-1, p)
1054                }
1055            }
1056            Flavor::NaN(err) => Self::nan(*err),
1057        }
1058    }
1059
1060    /// Computes the hyperbolic tangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1061    /// This function requires constants cache `cc` for computing the result.
1062    /// Precision is rounded upwards to the word size.
1063    /// The function returns NaN if the precision `p` is incorrect.
1064    pub fn tanh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1065        match &self.inner {
1066            Flavor::Value(v) => Self::result_to_ext(v.tanh(p, rm, cc), v.is_zero(), true),
1067            Flavor::Inf(s) => Self::from_i8(s.to_int(), p),
1068            Flavor::NaN(err) => Self::nan(*err),
1069        }
1070    }
1071
1072    fn half_pi(
1073        s: Sign,
1074        p: usize,
1075        rm: RoundingMode,
1076        cc: &mut Consts,
1077    ) -> Result<ExactNumNumber, Error> {
1078        let mut half_pi = cc.pi_num(p, rm)?;
1079
1080        half_pi.set_exponent(1);
1081        half_pi.set_sign(s);
1082
1083        Ok(half_pi)
1084    }
1085
1086    fn result_to_ext(
1087        res: Result<ExactNumNumber, Error>,
1088        is_dividend_zero: bool,
1089        is_same_sign: bool,
1090    ) -> ExactNum {
1091        match res {
1092            Err(e) => match e {
1093                Error::ExponentOverflow(s) => {
1094                    if s.is_positive() {
1095                        INF_POS
1096                    } else {
1097                        INF_NEG
1098                    }
1099                }
1100                Error::DivisionByZero => {
1101                    if is_dividend_zero {
1102                        NAN
1103                    } else if is_same_sign {
1104                        INF_POS
1105                    } else {
1106                        INF_NEG
1107                    }
1108                }
1109                Error::MemoryAllocation => Self::nan(Some(Error::MemoryAllocation)),
1110                Error::InvalidArgument => Self::nan(Some(Error::InvalidArgument)),
1111                Error::PrecisionRetryExhausted => Self::nan(Some(Error::PrecisionRetryExhausted)),
1112            },
1113            Ok(v) => ExactNum {
1114                inner: Flavor::Value(v),
1115            },
1116        }
1117    }
1118
1119    /// Returns the exponent of `self`, or None if `self` is Inf or NaN.
1120    pub fn exponent(&self) -> Option<Exponent> {
1121        match &self.inner {
1122            Flavor::Value(v) => Some(v.exponent()),
1123            _ => None,
1124        }
1125    }
1126
1127    /// Returns the number of significant bits used in the mantissa, or None if `self` is Inf or NaN.
1128    /// Normal numbers use all bits of the mantissa.
1129    /// Subnormal numbers use fewer bits than the mantissa can hold.
1130    pub fn precision(&self) -> Option<usize> {
1131        match &self.inner {
1132            Flavor::Value(v) => Some(v.precision()),
1133            _ => None,
1134        }
1135    }
1136
1137    /// Returns the maximum value for the specified precision `p`: all bits of the mantissa are set to 1,
1138    /// the exponent has the maximum possible value, and the sign is positive.
1139    /// Precision is rounded upwards to the word size.
1140    /// The function returns NaN if the precision `p` is incorrect.
1141    pub fn max_value(p: usize) -> Self {
1142        Self::result_to_ext(ExactNumNumber::max_value(p), false, true)
1143    }
1144
1145    /// Returns the minimum value for the specified precision `p`: all bits of the mantissa are set to 1, the exponent has the maximum possible value, and the sign is negative. Precision is rounded upwards to the word size.
1146    /// The function returns NaN if the precision `p` is incorrect.
1147    pub fn min_value(p: usize) -> Self {
1148        Self::result_to_ext(ExactNumNumber::min_value(p), false, true)
1149    }
1150
1151    /// Returns the minimum positive subnormal value for the specified precision `p`:
1152    /// only the least significant bit of the mantissa is set to 1, the exponent has
1153    /// the minimum possible value, and the sign is positive.
1154    /// Precision is rounded upwards to the word size.
1155    /// The function returns NaN if the precision `p` is incorrect.
1156    pub fn min_positive(p: usize) -> Self {
1157        Self::result_to_ext(ExactNumNumber::min_positive(p), false, true)
1158    }
1159
1160    /// Returns the minimum positive normal value for the specified precision `p`:
1161    /// only the most significant bit of the mantissa is set to 1, the exponent has
1162    /// the minimum possible value, and the sign is positive.
1163    /// Precision is rounded upwards to the word size.
1164    /// The function returns NaN if the precision `p` is incorrect.
1165    pub fn min_positive_normal(p: usize) -> Self {
1166        Self::result_to_ext(ExactNumNumber::min_positive_normal(p), false, true)
1167    }
1168
1169    /// Returns a new number with value `d` and the precision `p`. Precision is rounded upwards to the word size.
1170    /// The function returns NaN if the precision `p` is incorrect.
1171    pub fn from_word(d: Word, p: usize) -> Self {
1172        Self::result_to_ext(ExactNumNumber::from_word(d, p), false, true)
1173    }
1174
1175    /// Returns a copy of the number with the sign reversed.
1176    pub fn neg(&self) -> Self {
1177        let mut ret = self.clone();
1178        ret.inv_sign();
1179        ret
1180    }
1181
1182    /// Decomposes `self` into raw parts.
1183    /// The function returns a reference to a slice of words representing mantissa,
1184    /// numbers of significant bits in the mantissa, sign, exponent,
1185    /// and a bool value which specify whether the number is inexact.
1186    pub fn as_raw_parts(&self) -> Option<(&[Word], usize, Sign, Exponent, bool)> {
1187        if let Flavor::Value(v) = &self.inner {
1188            Some(v.as_raw_parts())
1189        } else {
1190            None
1191        }
1192    }
1193
1194    /// Constructs a number from the raw parts:
1195    ///
1196    ///  - `m` is the mantisaa.
1197    ///  - `n` is the number of significant bits in mantissa.
1198    ///  - `s` is the sign.
1199    ///  - `e` is the exponent.
1200    ///  - `inexact` specify whether number is inexact.
1201    ///
1202    /// This function returns NaN in the following situations:
1203    ///
1204    /// - `n` is larger than the number of bits in `m`.
1205    /// - `n` is smaller than the number of bits in `m`, but `m` does not represent corresponding subnormal number mantissa.
1206    /// - `n` is smaller than the number of bits in `m`, but `e` is not the minimum possible exponent.
1207    /// - `n` or the size of `m` is too large (larger than isize::MAX / 2 + EXPONENT_MIN).
1208    /// - `e` is less than EXPONENT_MIN or greater than EXPONENT_MAX.
1209    pub fn from_raw_parts(m: &[Word], n: usize, s: Sign, e: Exponent, inexact: bool) -> Self {
1210        Self::result_to_ext(
1211            crate::mantissa::Mantissa::from_raw_parts(m, n)
1212                .map(|mantissa| ExactNumNumber::from_raw_unchecked(mantissa, s, e, inexact)),
1213            false,
1214            true,
1215        )
1216    }
1217
1218    /// Constructs a number from the slice of words:
1219    ///
1220    ///  - `m` is the mantissa.
1221    ///  - `s` is the sign.
1222    ///  - `e` is the exponent.
1223    ///
1224    /// The function returns NaN if `e` is less than EXPONENT_MIN or greater than EXPONENT_MAX.
1225    pub fn from_words(m: &[Word], s: Sign, e: Exponent) -> Self {
1226        Self::result_to_ext(ExactNumNumber::from_words(m, s, e), false, true)
1227    }
1228
1229    /// Returns the sign of `self`, or None if `self` is NaN.
1230    pub fn sign(&self) -> Option<Sign> {
1231        match &self.inner {
1232            Flavor::Value(v) => Some(v.sign()),
1233            Flavor::Inf(s) => Some(*s),
1234            Flavor::NaN(_) => None,
1235        }
1236    }
1237
1238    /// Sets the exponent of `self`.
1239    /// Note that if `self` is subnormal, the exponent may not change, but the mantissa will shift instead.
1240    /// `e` will be clamped to the range from EXPONENT_MIN to EXPONENT_MAX if it's outside of the range.
1241    /// See example below.
1242    ///
1243    /// ## Examples
1244    ///
1245    /// ```
1246    /// # use zenith_float_num::ExactNum;
1247    /// # use zenith_float_num::EXPONENT_MIN;
1248    /// // construct a subnormal value.
1249    /// let mut n = ExactNum::min_positive(128);
1250    ///
1251    /// assert_eq!(n.exponent(), Some(EXPONENT_MIN));
1252    /// assert_eq!(n.precision(), Some(1));
1253    ///
1254    /// // increase exponent.
1255    /// let n_exp = n.exponent().expect("n is not NaN");
1256    /// n.set_exponent(n_exp + 1);
1257    ///
1258    /// // the outcome for subnormal number.
1259    /// assert_eq!(n.exponent(), Some(EXPONENT_MIN));
1260    /// assert_eq!(n.precision(), Some(2));
1261    /// ```
1262    pub fn set_exponent(&mut self, e: Exponent) {
1263        if let Flavor::Value(v) = &mut self.inner {
1264            v.set_exponent(e)
1265        }
1266    }
1267
1268    /// Returns the maximum mantissa length of `self` in bits regardless of whether `self` is normal or subnormal.
1269    pub fn mantissa_max_bit_len(&self) -> Option<usize> {
1270        if let Flavor::Value(v) = &self.inner {
1271            Some(v.mantissa_max_bit_len())
1272        } else {
1273            None
1274        }
1275    }
1276
1277    /// True when a finite value stores its mantissa on the stack (at most [`crate::INLINE_WORDS`] limbs).
1278    /// Inf and NaN return `false`.
1279    pub fn is_inline(&self) -> bool {
1280        match &self.inner {
1281            Flavor::Value(v) => v.is_inline(),
1282            Flavor::Inf(_) | Flavor::NaN(_) => false,
1283        }
1284    }
1285
1286    /// Sets the precision of `self` to `p`.
1287    /// If the new precision is smaller than the existing one, the number is rounded using specified rounding mode `rm`.
1288    ///
1289    /// ## Errors
1290    ///
1291    ///  - MemoryAllocation: failed to allocate memory for mantissa.
1292    ///  - InvalidArgument: the precision is incorrect.
1293    pub fn set_precision(&mut self, p: usize, rm: RoundingMode) -> Result<(), Error> {
1294        if let Flavor::Value(v) = &mut self.inner {
1295            v.set_precision(p, rm)
1296        } else {
1297            Ok(())
1298        }
1299    }
1300
1301    /// Computes the reciprocal of a number with precision `p`.
1302    /// The result is rounded using the rounding mode `rm`.
1303    /// Precision is rounded upwards to the word size.
1304    /// The function returns NaN if the precision `p` is incorrect.
1305    pub fn reciprocal(&self, p: usize, rm: RoundingMode) -> Self {
1306        match &self.inner {
1307            Flavor::Value(v) => Self::result_to_ext(v.reciprocal(p, rm), false, v.is_positive()),
1308            Flavor::Inf(s) => {
1309                let mut ret = Self::new(p);
1310                ret.set_sign(*s);
1311                ret
1312            }
1313            Flavor::NaN(err) => Self::nan(*err),
1314        }
1315    }
1316
1317    /// Sets the sign of `self`.
1318    pub fn set_sign(&mut self, s: Sign) {
1319        match &mut self.inner {
1320            Flavor::Value(v) => v.set_sign(s),
1321            Flavor::Inf(_) => self.inner = Flavor::Inf(s),
1322            Flavor::NaN(_) => {}
1323        };
1324    }
1325
1326    /// Returns the raw mantissa words of a number.
1327    pub fn mantissa_digits(&self) -> Option<&[Word]> {
1328        if let Flavor::Value(v) = &self.inner {
1329            Some(v.mantissa().digits())
1330        } else {
1331            None
1332        }
1333    }
1334
1335    /// Converts an array of digits in radix `rdx` to ExactNum with precision `p`.
1336    /// `digits` represents mantissa and is interpreted as a number smaller than 1 and greater or equal to 1/`rdx`.
1337    /// The first element in `digits` is the most significant digit.
1338    /// `e` is the exponent part of the number, such that the number can be represented as `digits` * `rdx` ^ `e`.
1339    /// Precision is rounded upwards to the word size.
1340    /// if `p` equals usize::MAX then the precision of the resulting number is determined automatically from the input.
1341    ///
1342    /// ## Examples
1343    ///
1344    /// Code below converts `-0.1234567₈ × 10₈^3₈` given in radix 8 to ExactNum.
1345    ///
1346    /// ``` rust
1347    /// # use zenith_float_num::{ExactNum, Sign, RoundingMode, Radix, Consts};
1348    /// let mut cc = Consts::new().expect("Constants cache initialized.");
1349    ///
1350    /// let n = ExactNum::convert_from_radix(
1351    ///     Sign::Neg,
1352    ///     &[1, 2, 3, 4, 5, 6, 7, 0],
1353    ///     3,
1354    ///     Radix::Oct,
1355    ///     64,
1356    ///     RoundingMode::None,
1357    ///     &mut cc);
1358    /// assert!(!n.is_nan());
1359    /// assert!(n.is_negative());
1360    /// ```
1361    ///
1362    /// ## Errors
1363    ///
1364    /// On error, the function returns NaN with the following associated error:
1365    ///
1366    ///  - MemoryAllocation: failed to allocate memory for mantissa.
1367    ///  - ExponentOverflow: the resulting exponent becomes greater than the maximum allowed value for the exponent.
1368    ///  - InvalidArgument: the precision is incorrect, or `digits` contains unacceptable digits for given radix,
1369    ///    or when `e` is less than EXPONENT_MIN or greater than EXPONENT_MAX.
1370    pub fn convert_from_radix(
1371        sign: Sign,
1372        digits: &[u8],
1373        e: Exponent,
1374        rdx: Radix,
1375        p: usize,
1376        rm: RoundingMode,
1377        cc: &mut Consts,
1378    ) -> Self {
1379        Self::result_to_ext(
1380            ExactNumNumber::convert_from_radix(sign, digits, e, rdx, p, rm, cc),
1381            false,
1382            true,
1383        )
1384    }
1385
1386    /// Converts `self` to radix `rdx` using rounding mode `rm`.
1387    /// The function returns sign, mantissa digits in radix `rdx`, and exponent such that the converted number
1388    /// can be represented as `mantissa digits` * `rdx` ^ `exponent`.
1389    /// The first element in the mantissa is the most significant digit.
1390    ///
1391    /// ## Examples
1392    ///
1393    /// ``` rust
1394    /// # use zenith_float_num::{ExactNum, Sign, RoundingMode, Radix, Consts};
1395    ///
1396    /// let mut cc = Consts::new().expect("Constants cache initialized.");
1397    /// let n = ExactNum::parse("123.45678", Radix::Dec, 64, RoundingMode::None, &mut cc);
1398    /// let (s, m, _e) = n.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc).expect("Conversion failed");
1399    /// assert_eq!(s, Sign::Pos);
1400    /// assert!(!m.is_empty());
1401    /// ```
1402    ///
1403    /// ## Errors
1404    ///
1405    ///  - MemoryAllocation: failed to allocate memory for mantissa.
1406    ///  - ExponentOverflow: the resulting exponent becomes greater than the maximum allowed value for the exponent.
1407    ///  - InvalidArgument: `self` is Inf or NaN.
1408    pub fn convert_to_radix(
1409        &self,
1410        rdx: Radix,
1411        rm: RoundingMode,
1412        cc: &mut Consts,
1413    ) -> Result<(Sign, Vec<u8>, Exponent), Error> {
1414        match &self.inner {
1415            Flavor::Value(v) => v.convert_to_radix(rdx, rm, cc),
1416            Flavor::NaN(_) => Err(Error::InvalidArgument),
1417            Flavor::Inf(_) => Err(Error::InvalidArgument),
1418        }
1419    }
1420
1421    /// Returns true if `self` is inexact. The function returns false if `self` is Inf or NaN.
1422    pub fn inexact(&self) -> bool {
1423        if let Flavor::Value(v) = &self.inner {
1424            v.inexact()
1425        } else {
1426            false
1427        }
1428    }
1429
1430    /// Marks `self` as inexact if `inexact` is true, or exact otherwise.
1431    /// The function has no effect if `self` is Inf or NaN.
1432    pub fn set_inexact(&mut self, inexact: bool) {
1433        if let Flavor::Value(v) = &mut self.inner {
1434            v.set_inexact(inexact);
1435        }
1436    }
1437
1438    /// Try to round and then set the precision to `p`, given `self` has `s` correct digits in mantissa.
1439    /// The function returns true if rounding succeeded, or if `self` is Inf or NaN.
1440    /// If the fuction returns `false`, `self` is still modified, and should be discarded.
1441    /// In case of an error, `self` will be set to NaN with an associated error.
1442    /// If the precision `p` is incorrect `self` will be set to NaN.
1443    pub fn try_set_precision(&mut self, p: usize, rm: RoundingMode, s: usize) -> bool {
1444        if let Flavor::Value(v) = &mut self.inner {
1445            v.try_set_precision(p, rm, s).unwrap_or_else(|e| {
1446                self.inner = Flavor::NaN(Some(e));
1447                true
1448            })
1449        } else {
1450            true
1451        }
1452    }
1453
1454    /// Split `self = m · 2^e` with `m` in `[0.5, 1)` (zeros return `(0, 0)`; Inf/NaN return `(self, 0)`).
1455    pub fn frexp(&self) -> (Self, Exponent) {
1456        match &self.inner {
1457            Flavor::Value(v) => match v.frexp() {
1458                Ok((m, e)) => (m.into(), e),
1459                Err(err) => (Self::nan(Some(err)), 0),
1460            },
1461            Flavor::Inf(_) | Flavor::NaN(_) => (self.clone(), 0),
1462        }
1463    }
1464
1465    /// `self · 2^n`. Alias of [`Self::scalb`].
1466    pub fn ldexp(&self, n: Exponent, p: usize, rm: RoundingMode) -> Self {
1467        match &self.inner {
1468            Flavor::Value(v) => Self::result_to_ext(v.ldexp(n, p, rm), v.is_zero(), true),
1469            Flavor::Inf(_) | Flavor::NaN(_) => self.clone(),
1470        }
1471    }
1472
1473    /// `self · 2^n` (IEEE `scalbn`).
1474    pub fn scalb(&self, n: Exponent, p: usize, rm: RoundingMode) -> Self {
1475        self.ldexp(n, p, rm)
1476    }
1477
1478    /// `floor(log2(|self|))` as a float. Zero becomes `-Inf`; Inf/NaN unchanged in kind.
1479    pub fn logb(&self, p: usize, rm: RoundingMode) -> Self {
1480        match &self.inner {
1481            Flavor::Value(v) => Self::result_to_ext(v.logb(p, rm), v.is_zero(), true),
1482            Flavor::Inf(_) => INF_POS,
1483            Flavor::NaN(err) => Self::nan(*err),
1484        }
1485    }
1486
1487    /// Integer `floor(log2(|self|))`. `None` for zero, Inf, or NaN.
1488    pub fn ilogb(&self) -> Option<Exponent> {
1489        match &self.inner {
1490            Flavor::Value(v) => v.ilogb().ok(),
1491            _ => None,
1492        }
1493    }
1494}
1495
1496impl Clone for ExactNum {
1497    fn clone(&self) -> Self {
1498        match &self.inner {
1499            Flavor::Value(v) => Self::result_to_ext(v.clone(), false, true),
1500            Flavor::Inf(s) => {
1501                if s.is_positive() {
1502                    INF_POS
1503                } else {
1504                    INF_NEG
1505                }
1506            }
1507            Flavor::NaN(err) => Self::nan(*err),
1508        }
1509    }
1510}
1511
1512macro_rules! gen_wrapper_arg {
1513    // function requires self as argument
1514    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1515        #[doc=$comment]
1516        pub fn $fname(&self$(,$arg: $arg_type)*) -> $ret {
1517            match &self.inner {
1518                Flavor::Value(v) => Self::result_to_ext(v.$fname($($arg,)*), v.is_zero(), true),
1519                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1520                Flavor::NaN(err) => Self::nan(*err),
1521            }
1522        }
1523    };
1524}
1525
1526macro_rules! gen_wrapper_arg_rm {
1527    // unwrap error, function requires self as argument
1528    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1529        #[doc=$comment]
1530        pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode) -> $ret {
1531            match &self.inner {
1532                Flavor::Value(v) => {
1533                    Self::result_to_ext(v.$fname($($arg,)* rm), v.is_zero(), true)
1534                },
1535                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1536                Flavor::NaN(err) => Self::nan(*err),
1537            }
1538        }
1539    };
1540}
1541
1542macro_rules! gen_wrapper_arg_rm_cc {
1543    // unwrap error, function requires self as argument
1544    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1545        #[doc=$comment]
1546        pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode, cc: &mut Consts) -> $ret {
1547            match &self.inner {
1548                Flavor::Value(v) => {
1549                    Self::result_to_ext(v.$fname($($arg,)* rm, cc), v.is_zero(), true)
1550                },
1551                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1552                Flavor::NaN(err) => Self::nan(*err),
1553            }
1554        }
1555    };
1556}
1557
1558macro_rules! gen_wrapper_log {
1559    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1560        #[doc=$comment]
1561        pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode, cc: &mut Consts) -> $ret {
1562            match &self.inner {
1563                Flavor::Value(v) => {
1564                    if v.is_zero() {
1565                        return INF_NEG;
1566                    }
1567                    Self::result_to_ext(v.$fname($($arg,)* rm, cc), v.is_zero(), true)
1568                },
1569                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1570                Flavor::NaN(err) => Self::nan(*err),
1571            }
1572        }
1573    };
1574}
1575
1576impl ExactNum {
1577    gen_wrapper_arg!(
1578        "Returns the absolute value of `self`.",
1579        abs,
1580        Self,
1581        { INF_POS },
1582        { INF_POS },
1583    );
1584    /// Returns a value with the magnitude of `self` and the sign of `sign`.
1585    pub fn copysign(&self, sign: &Self, p: usize, rm: RoundingMode) -> Self {
1586        if self.is_nan() {
1587            return self.clone();
1588        }
1589        let sign_num = match &sign.inner {
1590            Flavor::Value(v) => v.clone(),
1591            Flavor::Inf(s) => ExactNumNumber::from_i8(s.to_int(), p),
1592            Flavor::NaN(_) => ExactNumNumber::new(p),
1593        };
1594        let sign_num = match sign_num {
1595            Ok(v) => v,
1596            Err(e) => return Self::nan(Some(e)),
1597        };
1598        match &self.inner {
1599            Flavor::Value(v) => Self::result_to_ext(v.copysign(&sign_num, p, rm), false, true),
1600            Flavor::Inf(_) => {
1601                if sign.is_negative() || (sign.is_zero() && sign_num.is_negative()) {
1602                    INF_NEG
1603                } else {
1604                    INF_POS
1605                }
1606            }
1607            Flavor::NaN(err) => Self::nan(*err),
1608        }
1609    }
1610    /// Returns the next representable value from `self` toward `toward` at precision `p`.
1611    pub fn next_after(&self, toward: &Self, p: usize, rm: RoundingMode) -> Self {
1612        if self.is_nan() {
1613            return self.clone();
1614        }
1615        if toward.is_nan() {
1616            return toward.clone();
1617        }
1618        match (&self.inner, &toward.inner) {
1619            (Flavor::Value(v), Flavor::Value(t)) => {
1620                Self::result_to_ext(v.next_after(t, p, rm), false, true)
1621            }
1622            (Flavor::Inf(_), _) | (_, Flavor::Inf(_)) => self.clone(),
1623            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
1624        }
1625    }
1626    gen_wrapper_arg!("Returns the integer part of `self`.", int, Self, { NAN }, {
1627        NAN
1628    },);
1629    gen_wrapper_arg!(
1630        "Returns the fractional part of `self`.",
1631        fract,
1632        Self,
1633        { NAN },
1634        { NAN },
1635    );
1636    gen_wrapper_arg!(
1637        "Returns the smallest integer greater than or equal to `self`.",
1638        ceil,
1639        Self,
1640        { INF_POS },
1641        { INF_NEG },
1642    );
1643    gen_wrapper_arg!(
1644        "Returns the largest integer less than or equal to `self`.",
1645        floor,
1646        Self,
1647        { INF_POS },
1648        { INF_NEG },
1649    );
1650    gen_wrapper_arg_rm!("Returns the rounded number with `n` binary positions in the fractional part of the number using rounding mode `rm`.", 
1651        round,
1652        Self,
1653        { INF_POS },
1654        { INF_NEG },
1655        n,
1656        usize
1657    );
1658    gen_wrapper_arg_rm!(
1659        "Computes the square root of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1660        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1661        sqrt,
1662        Self,
1663        { INF_POS },
1664        { NAN },
1665        p,
1666        usize
1667    );
1668    gen_wrapper_arg_rm!(
1669        "Computes the cube root of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1670        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1671        cbrt,
1672        Self,
1673        { INF_POS },
1674        { INF_NEG },
1675        p,
1676        usize
1677    );
1678    /// Computes the `n`-th root of `self` with precision `p`. `n = 2` and `n = 3` delegate to [`sqrt`](Self::sqrt) and [`cbrt`](Self::cbrt).
1679    pub fn nth_root(&self, n: usize, p: usize, rm: RoundingMode) -> Self {
1680        if n == 0 {
1681            return Self::nan(Some(Error::InvalidArgument));
1682        }
1683        match &self.inner {
1684            Flavor::Value(v) => Self::result_to_ext(v.nth_root(n, p, rm), v.is_zero(), true),
1685            Flavor::Inf(s) => {
1686                if n % 2 == 0 {
1687                    if s.is_negative() {
1688                        NAN
1689                    } else {
1690                        INF_POS
1691                    }
1692                } else if s.is_negative() {
1693                    INF_NEG
1694                } else {
1695                    INF_POS
1696                }
1697            }
1698            Flavor::NaN(err) => Self::nan(*err),
1699        }
1700    }
1701    gen_wrapper_log!(
1702        "Computes the natural logarithm of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1703        This function requires constants cache `cc` for computing the result.
1704        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1705        ln,
1706        Self,
1707        { INF_POS },
1708        { NAN },
1709        p,
1710        usize
1711    );
1712    gen_wrapper_log!(
1713        "Computes the logarithm base 2 of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1714        This function requires constants cache `cc` for computing the result.
1715        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1716        log2,
1717        Self,
1718        { INF_POS },
1719        { NAN },
1720        p,
1721        usize
1722    );
1723    gen_wrapper_log!(
1724        "Computes the logarithm base 10 of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1725        This function requires constants cache `cc` for computing the result.
1726        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1727        log10,
1728        Self,
1729        { INF_POS },
1730        { NAN },
1731        p,
1732        usize
1733    );
1734    gen_wrapper_arg_rm_cc!(
1735        "Computes `e` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1736        This function requires constants cache `cc` for computing the result.
1737        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1738        exp,
1739        Self,
1740        { INF_POS },
1741        { Self::new(p) },
1742        p,
1743        usize
1744    );
1745    gen_wrapper_arg_rm_cc!(
1746        "Computes `2` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1747        This function requires constants cache `cc` for computing the result.
1748        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1749        exp2,
1750        Self,
1751        { INF_POS },
1752        { Self::new(p) },
1753        p,
1754        usize
1755    );
1756    gen_wrapper_arg_rm_cc!(
1757        "Computes `10` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1758        This function requires constants cache `cc` for computing the result.
1759        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1760        exp10,
1761        Self,
1762        { INF_POS },
1763        { Self::new(p) },
1764        p,
1765        usize
1766    );
1767    gen_wrapper_arg_rm_cc!(
1768        "Reduces `self` modulo `2π` into the interval `(-2π, 2π)` using precision `p` and rounding mode `rm`.
1769        This function requires constants cache `cc` for computing the result.",
1770        rem_pi,
1771        Self,
1772        { NAN },
1773        { NAN },
1774        p,
1775        usize
1776    );
1777
1778    gen_wrapper_arg_rm_cc!(
1779        "Computes the sine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1780        This function requires constants cache `cc` for computing the result.
1781        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1782        sin,
1783        Self,
1784        { NAN },
1785        { NAN },
1786        p,
1787        usize
1788    );
1789    gen_wrapper_arg_rm_cc!(
1790        "Computes the cosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1791        This function requires constants cache `cc` for computing the result.
1792        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1793        cos,
1794        Self,
1795        { NAN },
1796        { NAN },
1797        p,
1798        usize
1799    );
1800    /// Computes `(sin(self), cos(self))` with precision `p` using a shared argument reduction.
1801    pub fn sin_cos(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> (Self, Self) {
1802        match &self.inner {
1803            Flavor::Value(v) => match v.sin_cos(p, rm, cc) {
1804                Ok((s, c)) => (
1805                    Self::result_to_ext(Ok(s), false, true),
1806                    Self::result_to_ext(Ok(c), false, true),
1807                ),
1808                Err(e) => (Self::nan(Some(e)), Self::nan(Some(e))),
1809            },
1810            Flavor::Inf(_) => (NAN, NAN),
1811            Flavor::NaN(err) => (Self::nan(*err), Self::nan(*err)),
1812        }
1813    }
1814    gen_wrapper_arg_rm_cc!(
1815        "Computes the tangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1816        This function requires constants cache `cc` for computing the result.
1817        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1818        tan,
1819        Self,
1820        { NAN },
1821        { NAN },
1822        p,
1823        usize
1824    );
1825    gen_wrapper_arg_rm_cc!(
1826        "Computes the arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1827        This function requires constants cache `cc` for computing the result.
1828        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.", 
1829        asin,
1830        Self,
1831        {NAN},
1832        {NAN},
1833        p,
1834        usize
1835    );
1836    gen_wrapper_arg_rm_cc!(
1837        "Computes the arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1838        This function requires constants cache `cc` for computing the result.
1839        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1840        acos,
1841        Self,
1842        { NAN },
1843        { NAN },
1844        p,
1845        usize
1846    );
1847
1848    gen_wrapper_arg_rm_cc!(
1849        "Computes the hyperbolic sine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1850        This function requires constants cache cc for computing the result. 
1851        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1852        sinh,
1853        Self,
1854        { INF_POS },
1855        { INF_NEG },
1856        p,
1857        usize
1858    );
1859    gen_wrapper_arg_rm_cc!(
1860        "Computes the hyperbolic cosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1861        This function requires constants cache cc for computing the result. 
1862        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1863        cosh,
1864        Self,
1865        { INF_POS },
1866        { INF_POS },
1867        p,
1868        usize
1869    );
1870    /// Computes `(sinh(self), cosh(self))` with precision `p` using a single `exp(|x|)` evaluation.
1871    pub fn sinh_cosh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> (Self, Self) {
1872        match &self.inner {
1873            Flavor::Value(v) => match v.sinh_cosh(p, rm, cc) {
1874                Ok((s, c)) => (
1875                    Self::result_to_ext(Ok(s), false, true),
1876                    Self::result_to_ext(Ok(c), false, true),
1877                ),
1878                Err(Error::ExponentOverflow(s)) => {
1879                    if s.is_positive() {
1880                        (INF_POS, INF_POS)
1881                    } else {
1882                        (INF_NEG, INF_POS)
1883                    }
1884                }
1885                Err(e) => (Self::nan(Some(e)), Self::nan(Some(e))),
1886            },
1887            Flavor::Inf(s) => {
1888                if s.is_positive() {
1889                    (INF_POS, INF_POS)
1890                } else {
1891                    (INF_NEG, INF_POS)
1892                }
1893            }
1894            Flavor::NaN(err) => (Self::nan(*err), Self::nan(*err)),
1895        }
1896    }
1897    gen_wrapper_arg_rm_cc!(
1898        "Error function `erf(self)` with precision `p`.
1899
1900# Precision
1901
1902- Algorithm: Taylor series when `|x|.exponent() ≤ 2`; complementary asymptotic otherwise. Saturates to `±1` when `2|e| > p+4`.
1903- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on `|x| ≲ 4`.
1904- Thresholds: exponent cut `≤ 2` (not a named constant).
1905- MPFR oracle: yes, `|x| ≲ 4` under `mpfr-tests`. Complex `erf` on the real axis uses the same oracle; GNU MPC has no `mpc_erf`.",
1906        erf,
1907        Self,
1908        { ExactNum::from_u8(1, p) },
1909        { ExactNum::from_i8(-1, p) },
1910        p,
1911        usize
1912    );
1913    gen_wrapper_arg_rm_cc!(
1914        "Complementary error function `erfc(self) = 1 - erf(self)` with precision `p`.
1915
1916# Precision
1917
1918- Algorithm: `1 - erf` at extra working precision (same series / asymptotic as `erf`).
1919- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on `|x| ≲ 4`.
1920- MPFR oracle: yes, `|x| ≲ 4` under `mpfr-tests`.",
1921        erfc,
1922        Self,
1923        { Self::new(p) },
1924        { ExactNum::from_u8(2, p) },
1925        p,
1926        usize
1927    );
1928    gen_wrapper_arg_rm_cc!(
1929        "Gamma function `Γ(self)` with precision `p`. Poles at non-positive integers yield NaN (or +Inf at 0).
1930
1931# Precision
1932
1933- Algorithm: Stirling series for `ln Γ` then `exp`; reflection across the negative axis. Integer factorials for small positive integers.
1934- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on the oracle domain.
1935- MPFR oracle: yes, under `mpfr-tests`.",
1936        gamma,
1937        Self,
1938        { INF_POS },
1939        { NAN },
1940        p,
1941        usize
1942    );
1943    gen_wrapper_arg_rm_cc!(
1944        "`ln Γ(self)` for positive `self` with precision `p`.
1945
1946# Precision
1947
1948- Algorithm: Stirling series (Bernoulli) at working precision `p + WORD_BIT_SIZE`.
1949- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR on the oracle domain.
1950- MPFR oracle: yes, under `mpfr-tests`.",
1951        ln_gamma,
1952        Self,
1953        { INF_POS },
1954        { NAN },
1955        p,
1956        usize
1957    );
1958    gen_wrapper_arg_rm_cc!(
1959        "Digamma `ψ(self)`. Poles at non-positive integers. Reflection for z < 0.
1960
1961# Precision
1962
1963- Algorithm: recurrence to a large argument, then Bernoulli series; reflection for `z < 0`.
1964- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR `digamma` on `z > 0`.
1965- MPFR oracle: yes, `z > 0` under `mpfr-tests`.",
1966        digamma,
1967        Self,
1968        { INF_POS },
1969        { NAN },
1970        p,
1971        usize
1972    );
1973    /// Lower incomplete gamma `γ(self, x)` for `self > 0`, `x ≥ 0`.
1974    ///
1975    /// # Precision
1976    ///
1977    /// - Algorithm: power series in `x` at working precision; `+∞` in `x` returns `Γ(self)`.
1978    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
1979    /// - MPFR oracle: identity `γ(s,x)=Γ(s)−Γ(s,x)`; upper uses `mpfr_gamma_inc`.
1980    pub fn gammainc(&self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1981        match (&self.inner, &x.inner) {
1982            (Flavor::Value(s), Flavor::Value(xv)) => {
1983                Self::result_to_ext(s.gammainc(xv, p, rm, cc), xv.is_zero(), true)
1984            }
1985            (Flavor::Value(s), Flavor::Inf(sx)) => {
1986                if sx.is_positive() {
1987                    Self::result_to_ext(s.gamma(p, rm, cc), false, true)
1988                } else {
1989                    NAN
1990                }
1991            }
1992            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
1993            (Flavor::Inf(_), _) => NAN,
1994        }
1995    }
1996    /// Upper incomplete gamma `Γ(self, x)` for `self > 0`, `x ≥ 0`.
1997    ///
1998    /// # Precision
1999    ///
2000    /// - Algorithm: `Γ(self) - γ(self, x)` at working precision; `+∞` in `x` returns 0.
2001    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2002    /// - MPFR oracle: yes, `mpfr_gamma_inc` under `mpfr-tests`.
2003    pub fn gammainc_upper(&self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2004        match (&self.inner, &x.inner) {
2005            (Flavor::Value(s), Flavor::Value(xv)) => {
2006                Self::result_to_ext(s.gammainc_upper(xv, p, rm, cc), xv.is_zero(), true)
2007            }
2008            (Flavor::Value(_), Flavor::Inf(sx)) => {
2009                if sx.is_positive() {
2010                    Self::new(p)
2011                } else {
2012                    NAN
2013                }
2014            }
2015            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2016            (Flavor::Inf(_), _) => NAN,
2017        }
2018    }
2019    gen_wrapper_arg_rm_cc!(
2020        "Exponential integral `Ei(self)` (principal value for `self < 0`). `0` is a pole.
2021
2022# Precision
2023
2024- Algorithm: power series for moderate `|x|`; factorial asymptotic when `|x|` is large (`exponent() > 6` and `|x| ≳ 0.7 p`).
2025- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2026- MPFR oracle: yes, `mpfr_eint` under `mpfr-tests`.",
2027        ei,
2028        Self,
2029        { INF_POS },
2030        { Self::new(p) },
2031        p,
2032        usize
2033    );
2034    /// Sine integral `Si(self)`. `+∞ → π/2`, `−∞ → −π/2`.
2035    ///
2036    /// # Precision
2037    ///
2038    /// - Algorithm: series, or auxiliary `f,g` asymptotic on the same cut as `Ei`.
2039    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2040    /// - MPFR oracle: no (`Si` odd, `Si(0)=0`, `Si(+∞)=π/2`).
2041    pub fn si(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2042        match &self.inner {
2043            Flavor::Value(v) => Self::result_to_ext(v.si(p, rm, cc), v.is_zero(), true),
2044            Flavor::Inf(s) => Self::result_to_ext(Self::half_pi(*s, p, rm, cc), false, true),
2045            Flavor::NaN(err) => Self::nan(*err),
2046        }
2047    }
2048    gen_wrapper_arg_rm_cc!(
2049        "Cosine integral `Ci(self)` for `self > 0`.
2050
2051# Precision
2052
2053- Algorithm: series, or auxiliary `f,g` asymptotic (same `|x|` cut as `Ei`). Near-zero is a pole.
2054- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2055- MPFR oracle: no (identity / series golds; GNU MPFR has no `Si`/`Ci`).",
2056        ci,
2057        Self,
2058        { Self::new(p) },
2059        { NAN },
2060        p,
2061        usize
2062    );
2063    gen_wrapper_arg_rm_cc!(
2064        "Logarithmic integral `li(self) = Ei(ln self)` for `self > 0`, `self ≠ 1`.
2065
2066# Precision
2067
2068- Algorithm: `Ei(ln self)` at extra working precision (inherits `Ei` series / asymptotic).
2069- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2070- MPFR oracle: no (`li(e)=Ei(1)` identity).",
2071        li,
2072        Self,
2073        { INF_POS },
2074        { NAN },
2075        p,
2076        usize
2077    );
2078    /// Fresnel sine integral `S(self)`. `±∞ → ±1/2`.
2079    ///
2080    /// # Precision
2081    ///
2082    /// - Algorithm: series, or auxiliary `f,g` when `|x|.exponent() ≥ 8` (or `3 x² > p`).
2083    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2084    /// - MPFR oracle: no (`S` odd, `S(0)=0`, `S(+∞)=1/2`).
2085    pub fn fresnel_s(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2086        self.fresnel_sc_ext(true, p, rm, cc)
2087    }
2088
2089    /// Fresnel cosine integral `C(self)`. `±∞ → ±1/2`.
2090    ///
2091    /// # Precision
2092    ///
2093    /// - Algorithm: same series / auxiliary `f,g` split as [`Self::fresnel_s`].
2094    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2095    /// - MPFR oracle: no (same identities as [`Self::fresnel_s`]).
2096    pub fn fresnel_c(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2097        self.fresnel_sc_ext(false, p, rm, cc)
2098    }
2099
2100    fn fresnel_sc_ext(&self, sine: bool, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2101        match &self.inner {
2102            Flavor::Value(v) => {
2103                let inner = if sine { v.fresnel_s(p, rm, cc) } else { v.fresnel_c(p, rm, cc) };
2104                Self::result_to_ext(inner, v.is_zero(), true)
2105            }
2106            Flavor::Inf(s) => {
2107                let mut half = ExactNum::from_u8(1, p);
2108                half.set_exponent(0);
2109                half.set_sign(*s);
2110                half
2111            }
2112            Flavor::NaN(err) => Self::nan(*err),
2113        }
2114    }
2115
2116    /// Airy \(\mathrm{Ai}(\mathrm{self})\). \(+\infty\to 0\); \(-\infty\) has no limit → NaN.
2117    ///
2118    /// # Precision
2119    ///
2120    /// - Algorithm: power series for `|x| < AIRY_SERIES_THRESHOLD` (`8`); asymptotic otherwise.
2121    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2122    /// - MPFR oracle: yes, `mpfr_ai` under `mpfr-tests`.
2123    pub fn ai(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2124        match &self.inner {
2125            Flavor::Value(v) => Self::result_to_ext(v.ai(p, rm, cc), v.is_zero(), true),
2126            Flavor::Inf(s) => {
2127                if s.is_positive() {
2128                    Self::new(p)
2129                } else {
2130                    NAN
2131                }
2132            }
2133            Flavor::NaN(err) => Self::nan(*err),
2134        }
2135    }
2136
2137    /// Airy \(\mathrm{Bi}(\mathrm{self})\). \(+\infty\to+\infty\); \(-\infty\) has no limit → NaN.
2138    ///
2139    /// # Precision
2140    ///
2141    /// - Algorithm: same `AIRY_SERIES_THRESHOLD = 8` split as [`Self::ai`].
2142    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2143    /// - MPFR oracle: no (`Ai Bi' − Ai' Bi = 1/π`; GNU MPFR has no `Bi`).
2144    pub fn bi(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2145        match &self.inner {
2146            Flavor::Value(v) => Self::result_to_ext(v.bi(p, rm, cc), v.is_zero(), true),
2147            Flavor::Inf(s) => {
2148                if s.is_positive() {
2149                    INF_POS
2150                } else {
2151                    NAN
2152                }
2153            }
2154            Flavor::NaN(err) => Self::nan(*err),
2155        }
2156    }
2157
2158    /// \(\mathrm{Ai}'(\mathrm{self})\). \(+\infty\to 0\); \(-\infty\) → NaN.
2159    ///
2160    /// # Precision
2161    ///
2162    /// - Algorithm: differentiated series / asymptotic; `AIRY_SERIES_THRESHOLD = 8`.
2163    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2164    /// - MPFR oracle: no.
2165    pub fn ai_prime(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2166        match &self.inner {
2167            Flavor::Value(v) => Self::result_to_ext(v.ai_prime(p, rm, cc), v.is_zero(), true),
2168            Flavor::Inf(s) => {
2169                if s.is_positive() {
2170                    Self::new(p)
2171                } else {
2172                    NAN
2173                }
2174            }
2175            Flavor::NaN(err) => Self::nan(*err),
2176        }
2177    }
2178
2179    /// \(\mathrm{Bi}'(\mathrm{self})\). \(+\infty\to+\infty\); \(-\infty\) → NaN.
2180    ///
2181    /// # Precision
2182    ///
2183    /// - Algorithm: differentiated series / asymptotic; `AIRY_SERIES_THRESHOLD = 8`.
2184    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2185    /// - MPFR oracle: no.
2186    pub fn bi_prime(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2187        match &self.inner {
2188            Flavor::Value(v) => Self::result_to_ext(v.bi_prime(p, rm, cc), v.is_zero(), true),
2189            Flavor::Inf(s) => {
2190                if s.is_positive() {
2191                    INF_POS
2192                } else {
2193                    NAN
2194                }
2195            }
2196            Flavor::NaN(err) => Self::nan(*err),
2197        }
2198    }
2199
2200    /// Bessel function of the first kind `J_n(self)` for integer order `n`.
2201    ///
2202    /// # Precision
2203    ///
2204    /// - Algorithm: power series; Miller recurrence for large `n` (`n ≤ 1024`).
2205    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`). 1 ULP vs MPFR `jn` for `n = 0,1,2`.
2206    /// - MPFR oracle: yes, `n = 0,1,2` under `mpfr-tests`.
2207    pub fn bessel_j(&self, n: usize, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2208        match &self.inner {
2209            Flavor::Value(v) => Self::result_to_ext(v.bessel_j(n, p, rm, cc), v.is_zero(), true),
2210            Flavor::Inf(_) => NAN,
2211            Flavor::NaN(err) => Self::nan(*err),
2212        }
2213    }
2214
2215    fn bessel_nu_ext(
2216        &self,
2217        nu: &Self,
2218        p: usize,
2219        rm: RoundingMode,
2220        cc: &mut Consts,
2221        f: fn(
2222            &ExactNumNumber,
2223            &ExactNumNumber,
2224            usize,
2225            RoundingMode,
2226            &mut Consts,
2227        ) -> Result<ExactNumNumber, Error>,
2228    ) -> Self {
2229        match (&self.inner, &nu.inner) {
2230            (Flavor::Value(x), Flavor::Value(n)) => {
2231                Self::result_to_ext(f(x, n, p, rm, cc), x.is_zero(), true)
2232            }
2233            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2234            _ => NAN,
2235        }
2236    }
2237
2238    /// \(J_ν(\mathrm{self})\) for real order `nu`.
2239    ///
2240    /// # Precision
2241    ///
2242    /// - Algorithm: series in `x`; integer `ν` delegates to [`Self::bessel_j`].
2243    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2244    /// - MPFR oracle: no (identity golds).
2245    pub fn bessel_j_nu(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2246        self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_j_nu)
2247    }
2248
2249    /// \(Y_ν(\mathrm{self})\) for `self > 0`.
2250    ///
2251    /// # Precision
2252    ///
2253    /// - Algorithm: Wronskian / series from \(J_ν\); cut on \((-\infty, 0]\).
2254    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2255    /// - MPFR oracle: yes, `mpfr_yn` for `n = 0,1` under `mpfr-tests`.
2256    pub fn bessel_y(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2257        self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_y)
2258    }
2259
2260    /// \(I_ν(\mathrm{self})\).
2261    ///
2262    /// # Precision
2263    ///
2264    /// - Algorithm: series; \(I_ν(z) = i^{-ν} J_ν(iz)\) for the complex path.
2265    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2266    /// - MPFR oracle: no.
2267    pub fn bessel_i(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2268        self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_i)
2269    }
2270
2271    /// \(K_ν(\mathrm{self})\) for `self > 0`. \(K_{-ν}=K_ν\).
2272    ///
2273    /// # Precision
2274    ///
2275    /// - Algorithm: series / Temme; large-`|x|` asymptotic `k_asymptotic`.
2276    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2277    /// - MPFR oracle: no.
2278    pub fn bessel_k(&self, nu: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2279        self.bessel_nu_ext(nu, p, rm, cc, ExactNumNumber::bessel_k)
2280    }
2281    gen_wrapper_arg_rm_cc!(
2282        "Complete elliptic `K(self)`. Parameter `m = k²`. `m = 1` is `+∞`; `m > 1` uses the reciprocal-modulus transform.
2283
2284# Precision
2285
2286- Algorithm: Carlson `R_F` duplication; cap `CARLSON_DUPE_MAX = 128`.
2287- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2288- MPFR oracle: no (identity golds; GNU MPFR has no Carlson `K`).",
2289        elliptic_k,
2290        Self,
2291        { NAN },
2292        { NAN },
2293        p,
2294        usize
2295    );
2296    gen_wrapper_arg_rm_cc!(
2297        "Complete elliptic `E(self)` for `self ≤ 1`. `E(1) = 1`.
2298
2299# Precision
2300
2301- Algorithm: Carlson `R_F` / `R_D`; `CARLSON_DUPE_MAX = 128`.
2302- Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2303- MPFR oracle: no.",
2304        elliptic_e_complete,
2305        Self,
2306        { NAN },
2307        { NAN },
2308        p,
2309        usize
2310    );
2311    /// Incomplete `F(self | m)` for `|self| ≤ 1`. `self = sin φ`, `m = k²`.
2312    ///
2313    /// # Precision
2314    ///
2315    /// - Algorithm: Carlson `R_F`; `CARLSON_DUPE_MAX = 128`.
2316    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2317    /// - MPFR oracle: no.
2318    pub fn elliptic_f(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2319        match (&self.inner, &m.inner) {
2320            (Flavor::Value(x), Flavor::Value(mv)) => {
2321                Self::result_to_ext(x.elliptic_f(mv, p, rm, cc), x.is_zero(), true)
2322            }
2323            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2324            _ => NAN,
2325        }
2326    }
2327    /// Incomplete `E(self | m)` for `|self| ≤ 1`.
2328    ///
2329    /// # Precision
2330    ///
2331    /// - Algorithm: Carlson `R_F` / `R_D`; `CARLSON_DUPE_MAX = 128`.
2332    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2333    /// - MPFR oracle: no.
2334    pub fn elliptic_e(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2335        match (&self.inner, &m.inner) {
2336            (Flavor::Value(x), Flavor::Value(mv)) => {
2337                Self::result_to_ext(x.elliptic_e(mv, p, rm, cc), x.is_zero(), true)
2338            }
2339            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2340            _ => NAN,
2341        }
2342    }
2343    /// Complete `Π(self, m)` for `self < 1`, `m < 1`.
2344    ///
2345    /// # Precision
2346    ///
2347    /// - Algorithm: Carlson `R_J`; `CARLSON_DUPE_MAX = 128`.
2348    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2349    /// - MPFR oracle: no.
2350    pub fn elliptic_pi_complete(
2351        &self,
2352        m: &Self,
2353        p: usize,
2354        rm: RoundingMode,
2355        cc: &mut Consts,
2356    ) -> Self {
2357        match (&self.inner, &m.inner) {
2358            (Flavor::Value(n), Flavor::Value(mv)) => {
2359                Self::result_to_ext(n.elliptic_pi_complete(mv, p, rm, cc), false, true)
2360            }
2361            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2362            _ => NAN,
2363        }
2364    }
2365    /// Incomplete `Π(self; x | m)`.
2366    ///
2367    /// # Precision
2368    ///
2369    /// - Algorithm: Carlson `R_J`; `CARLSON_DUPE_MAX = 128`.
2370    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2371    /// - MPFR oracle: no.
2372    pub fn elliptic_pi(
2373        &self,
2374        x: &Self,
2375        m: &Self,
2376        p: usize,
2377        rm: RoundingMode,
2378        cc: &mut Consts,
2379    ) -> Self {
2380        match (&self.inner, &x.inner, &m.inner) {
2381            (Flavor::Value(n), Flavor::Value(xv), Flavor::Value(mv)) => {
2382                Self::result_to_ext(n.elliptic_pi(xv, mv, p, rm, cc), xv.is_zero(), true)
2383            }
2384            (Flavor::NaN(err), _, _) | (_, Flavor::NaN(err), _) | (_, _, Flavor::NaN(err)) => {
2385                Self::nan(*err)
2386            }
2387            _ => NAN,
2388        }
2389    }
2390    /// Jacobi amplitude `am(self | m)`. Parameter `m = k² ∈ [0, 1]`.
2391    ///
2392    /// # Precision
2393    ///
2394    /// - Algorithm: AGM / descending Landen; cap `JACOBI_AGM_MAX = 128`. \(m=0\) is trig; \(m=1\) is hyperbolic.
2395    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2396    /// - MPFR oracle: no (identity golds; GNU MPFR has no Jacobi `sn`).
2397    pub fn jacobi_am(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2398        match (&self.inner, &m.inner) {
2399            (Flavor::Value(u), Flavor::Value(mv)) => {
2400                Self::result_to_ext(u.jacobi_am(mv, p, rm, cc), u.is_zero(), true)
2401            }
2402            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2403            _ => NAN,
2404        }
2405    }
2406    /// `sn(self | m)`. Parameter `m = k² ∈ [0, 1]`.
2407    /// The inverse on `(-K, K)` is [`Self::elliptic_f`]: `F(sn(u|m)|m) = u`.
2408    ///
2409    /// # Precision
2410    ///
2411    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2412    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2413    /// - MPFR oracle: no.
2414    pub fn jacobi_sn(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2415        match (&self.inner, &m.inner) {
2416            (Flavor::Value(u), Flavor::Value(mv)) => {
2417                Self::result_to_ext(u.jacobi_sn(mv, p, rm, cc), u.is_zero(), true)
2418            }
2419            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2420            _ => NAN,
2421        }
2422    }
2423    /// `cn(self | m)`. Parameter `m = k² ∈ [0, 1]`.
2424    ///
2425    /// # Precision
2426    ///
2427    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2428    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2429    /// - MPFR oracle: no.
2430    pub fn jacobi_cn(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2431        match (&self.inner, &m.inner) {
2432            (Flavor::Value(u), Flavor::Value(mv)) => {
2433                Self::result_to_ext(u.jacobi_cn(mv, p, rm, cc), u.is_zero(), true)
2434            }
2435            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2436            _ => NAN,
2437        }
2438    }
2439    /// `dn(self | m)`. Parameter `m = k² ∈ [0, 1]`.
2440    ///
2441    /// # Precision
2442    ///
2443    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2444    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2445    /// - MPFR oracle: no.
2446    pub fn jacobi_dn(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2447        match (&self.inner, &m.inner) {
2448            (Flavor::Value(u), Flavor::Value(mv)) => {
2449                Self::result_to_ext(u.jacobi_dn(mv, p, rm, cc), false, true)
2450            }
2451            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2452            _ => NAN,
2453        }
2454    }
2455    /// `cd(self | m) = cn / dn`. Parameter `m = k² ∈ [0, 1]`.
2456    ///
2457    /// # Precision
2458    ///
2459    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2460    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2461    /// - MPFR oracle: no.
2462    pub fn jacobi_cd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2463        match (&self.inner, &m.inner) {
2464            (Flavor::Value(u), Flavor::Value(mv)) => {
2465                Self::result_to_ext(u.jacobi_cd(mv, p, rm, cc), false, true)
2466            }
2467            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2468            _ => NAN,
2469        }
2470    }
2471    /// `ns(self | m) = 1/sn`.
2472    ///
2473    /// # Precision
2474    ///
2475    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2476    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2477    /// - MPFR oracle: no.
2478    pub fn jacobi_ns(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2479        match (&self.inner, &m.inner) {
2480            (Flavor::Value(u), Flavor::Value(mv)) => {
2481                Self::result_to_ext(u.jacobi_ns(mv, p, rm, cc), false, true)
2482            }
2483            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2484            _ => NAN,
2485        }
2486    }
2487    /// `nc(self | m) = 1/cn`.
2488    ///
2489    /// # Precision
2490    ///
2491    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2492    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2493    /// - MPFR oracle: no.
2494    pub fn jacobi_nc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2495        match (&self.inner, &m.inner) {
2496            (Flavor::Value(u), Flavor::Value(mv)) => {
2497                Self::result_to_ext(u.jacobi_nc(mv, p, rm, cc), false, true)
2498            }
2499            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2500            _ => NAN,
2501        }
2502    }
2503    /// `nd(self | m) = 1/dn`.
2504    ///
2505    /// # Precision
2506    ///
2507    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2508    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2509    /// - MPFR oracle: no.
2510    pub fn jacobi_nd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2511        match (&self.inner, &m.inner) {
2512            (Flavor::Value(u), Flavor::Value(mv)) => {
2513                Self::result_to_ext(u.jacobi_nd(mv, p, rm, cc), false, true)
2514            }
2515            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2516            _ => NAN,
2517        }
2518    }
2519    /// `sc(self | m) = sn/cn`.
2520    ///
2521    /// # Precision
2522    ///
2523    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2524    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2525    /// - MPFR oracle: no.
2526    pub fn jacobi_sc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2527        match (&self.inner, &m.inner) {
2528            (Flavor::Value(u), Flavor::Value(mv)) => {
2529                Self::result_to_ext(u.jacobi_sc(mv, p, rm, cc), false, true)
2530            }
2531            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2532            _ => NAN,
2533        }
2534    }
2535    /// `sd(self | m) = sn/dn`.
2536    ///
2537    /// # Precision
2538    ///
2539    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2540    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2541    /// - MPFR oracle: no.
2542    pub fn jacobi_sd(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2543        match (&self.inner, &m.inner) {
2544            (Flavor::Value(u), Flavor::Value(mv)) => {
2545                Self::result_to_ext(u.jacobi_sd(mv, p, rm, cc), false, true)
2546            }
2547            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2548            _ => NAN,
2549        }
2550    }
2551    /// `cs(self | m) = cn/sn`.
2552    ///
2553    /// # Precision
2554    ///
2555    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2556    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2557    /// - MPFR oracle: no.
2558    pub fn jacobi_cs(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2559        match (&self.inner, &m.inner) {
2560            (Flavor::Value(u), Flavor::Value(mv)) => {
2561                Self::result_to_ext(u.jacobi_cs(mv, p, rm, cc), false, true)
2562            }
2563            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2564            _ => NAN,
2565        }
2566    }
2567    /// `ds(self | m) = dn/sn`.
2568    ///
2569    /// # Precision
2570    ///
2571    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2572    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2573    /// - MPFR oracle: no.
2574    pub fn jacobi_ds(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2575        match (&self.inner, &m.inner) {
2576            (Flavor::Value(u), Flavor::Value(mv)) => {
2577                Self::result_to_ext(u.jacobi_ds(mv, p, rm, cc), false, true)
2578            }
2579            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2580            _ => NAN,
2581        }
2582    }
2583    /// `dc(self | m) = dn/cn`.
2584    ///
2585    /// # Precision
2586    ///
2587    /// - Algorithm: AGM amplitude; cap `JACOBI_AGM_MAX = 128`.
2588    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2589    /// - MPFR oracle: no.
2590    pub fn jacobi_dc(&self, m: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2591        match (&self.inner, &m.inner) {
2592            (Flavor::Value(u), Flavor::Value(mv)) => {
2593                Self::result_to_ext(u.jacobi_dc(mv, p, rm, cc), false, true)
2594            }
2595            (Flavor::NaN(err), _) | (_, Flavor::NaN(err)) => Self::nan(*err),
2596            _ => NAN,
2597        }
2598    }
2599    /// Legendre \(P_n(\mathrm{self})\) for integer `n`.
2600    ///
2601    /// # Precision
2602    ///
2603    /// - Algorithm: three-term recurrence at `p + O(n)` bits. Cap `ORTHOPOLY_N_MAX`.
2604    /// - Bound: working-precision recurrence (not a Ziv leaf).
2605    /// - MPFR oracle: no.
2606    pub fn legendre_p(&self, n: u32, p: usize, rm: RoundingMode) -> Self {
2607        match &self.inner {
2608            Flavor::Value(v) => Self::result_to_ext(v.legendre_p(n, p, rm), false, true),
2609            Flavor::Inf(_) => NAN,
2610            Flavor::NaN(err) => Self::nan(*err),
2611        }
2612    }
2613    /// Associated \(P_n^m(\mathrm{self})\) (Condon–Shortley).
2614    ///
2615    /// # Precision
2616    ///
2617    /// - Algorithm: recurrence from \(P_n\); Condon–Shortley phase.
2618    /// - Bound: working-precision recurrence (not a Ziv leaf).
2619    /// - MPFR oracle: no.
2620    pub fn assoc_legendre_p(&self, n: u32, m: i32, p: usize, rm: RoundingMode) -> Self {
2621        match &self.inner {
2622            Flavor::Value(v) => Self::result_to_ext(v.assoc_legendre_p(n, m, p, rm), false, true),
2623            Flavor::Inf(_) => NAN,
2624            Flavor::NaN(err) => Self::nan(*err),
2625        }
2626    }
2627    /// Gaussian \({}_2F_1(\mathrm{self}, b; c; z)\).
2628    ///
2629    /// # Precision
2630    ///
2631    /// - Algorithm: series for `|z| < 1`; Gauss at `z = 1`; Pfaff / continuation. Cap `HYPERGEOM_TERM_MAX = 10_000`.
2632    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`) when the series converges.
2633    /// - MPFR oracle: no.
2634    pub fn hypergeom_2f1(
2635        &self,
2636        b: &Self,
2637        c: &Self,
2638        z: &Self,
2639        p: usize,
2640        rm: RoundingMode,
2641        cc: &mut Consts,
2642    ) -> Self {
2643        match (&self.inner, &b.inner, &c.inner, &z.inner) {
2644            (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(cv), Flavor::Value(zv)) => {
2645                Self::result_to_ext(a.hypergeom_2f1(bv, cv, zv, p, rm, cc), zv.is_zero(), true)
2646            }
2647            (Flavor::NaN(err), _, _, _)
2648            | (_, Flavor::NaN(err), _, _)
2649            | (_, _, Flavor::NaN(err), _)
2650            | (_, _, _, Flavor::NaN(err)) => Self::nan(*err),
2651            _ => NAN,
2652        }
2653    }
2654    /// Regularized incomplete beta \(I_x(a=\mathrm{self}, b)\).
2655    ///
2656    /// # Precision
2657    ///
2658    /// - Algorithm: series / continued fraction in `x ∈ [0, 1]` for `a > 0`, `b > 0`.
2659    /// - Bound: Ziv correct-rounding (`MAX_PREC_RETRY`).
2660    /// - MPFR oracle: no.
2661    pub fn betainc(&self, b: &Self, x: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2662        match (&self.inner, &b.inner, &x.inner) {
2663            (Flavor::Value(a), Flavor::Value(bv), Flavor::Value(xv)) => {
2664                Self::result_to_ext(a.betainc(bv, xv, p, rm, cc), xv.is_zero(), true)
2665            }
2666            (Flavor::NaN(err), _, _) | (_, Flavor::NaN(err), _) | (_, _, Flavor::NaN(err)) => {
2667                Self::nan(*err)
2668            }
2669            _ => NAN,
2670        }
2671    }
2672    gen_wrapper_arg_rm_cc!(
2673        "Computes the hyperbolic arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2674        This function requires constants cache `cc` for computing the result.
2675        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2676        asinh,
2677        Self,
2678        { INF_POS },
2679        { INF_NEG },
2680        p,
2681        usize
2682    );
2683    gen_wrapper_arg_rm_cc!(
2684        "Computes the hyperbolic arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2685        This function requires constants cache `cc` for computing the result.
2686        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2687        acosh,
2688        Self,
2689        { INF_POS },
2690        { NAN },
2691        p,
2692        usize
2693    );
2694    gen_wrapper_arg_rm_cc!(
2695        "Computes the hyperbolic arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
2696        This function requires constants cache `cc` for computing the result.
2697        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
2698        atanh,
2699        Self,
2700        { NAN },
2701        { NAN },
2702        p,
2703        usize
2704    );
2705}
2706
2707macro_rules! impl_int_conv {
2708    ($s:ty, $from_s:ident) => {
2709        impl ExactNum {
2710            /// Constructs ExactNum with precision `p` from an integer value `i`.
2711            /// Precision is rounded upwards to the word size.
2712            /// The function returns NaN if the precision `p` is incorrect.
2713            pub fn $from_s(i: $s, p: usize) -> Self {
2714                Self::result_to_ext(ExactNumNumber::$from_s(i, p), false, true)
2715            }
2716        }
2717    };
2718}
2719
2720impl_int_conv!(i8, from_i8);
2721impl_int_conv!(i16, from_i16);
2722impl_int_conv!(i32, from_i32);
2723impl_int_conv!(i64, from_i64);
2724impl_int_conv!(i128, from_i128);
2725
2726impl_int_conv!(u8, from_u8);
2727impl_int_conv!(u16, from_u16);
2728impl_int_conv!(u32, from_u32);
2729impl_int_conv!(u64, from_u64);
2730impl_int_conv!(u128, from_u128);
2731
2732impl From<ExactNumNumber> for ExactNum {
2733    fn from(x: ExactNumNumber) -> Self {
2734        ExactNum {
2735            inner: Flavor::Value(x),
2736        }
2737    }
2738}
2739
2740#[cfg(feature = "std")]
2741use core::{
2742    fmt::{Binary, Display, Formatter, Octal, UpperHex},
2743    str::FromStr,
2744};
2745
2746use core::{cmp::Eq, cmp::Ordering, cmp::PartialEq, cmp::PartialOrd, ops::Neg};
2747
2748impl Neg for ExactNum {
2749    type Output = ExactNum;
2750    fn neg(mut self) -> Self::Output {
2751        self.inv_sign();
2752        self
2753    }
2754}
2755
2756impl Neg for &ExactNum {
2757    type Output = ExactNum;
2758    fn neg(self) -> Self::Output {
2759        let mut ret = self.clone();
2760        ret.inv_sign();
2761        ret
2762    }
2763}
2764
2765//
2766// ordering traits
2767//
2768
2769impl PartialEq for ExactNum {
2770    fn eq(&self, other: &Self) -> bool {
2771        let cmp_result = ExactNum::cmp(self, other);
2772        matches!(cmp_result, Some(0))
2773    }
2774}
2775
2776impl<'a> PartialEq<&'a ExactNum> for ExactNum {
2777    fn eq(&self, other: &&'a ExactNum) -> bool {
2778        let cmp_result = ExactNum::cmp(self, other);
2779        matches!(cmp_result, Some(0))
2780    }
2781}
2782
2783impl Eq for ExactNum {}
2784
2785impl PartialOrd for ExactNum {
2786    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2787        let cmp_result = ExactNum::cmp(self, other);
2788        match cmp_result {
2789            Some(v) => {
2790                if v > 0 {
2791                    Some(Ordering::Greater)
2792                } else if v < 0 {
2793                    Some(Ordering::Less)
2794                } else {
2795                    Some(Ordering::Equal)
2796                }
2797            }
2798            None => None,
2799        }
2800    }
2801}
2802
2803impl<'a> PartialOrd<&'a ExactNum> for ExactNum {
2804    fn partial_cmp(&self, other: &&'a ExactNum) -> Option<Ordering> {
2805        let cmp_result = ExactNum::cmp(self, other);
2806        match cmp_result {
2807            Some(v) => {
2808                if v > 0 {
2809                    Some(Ordering::Greater)
2810                } else if v < 0 {
2811                    Some(Ordering::Less)
2812                } else {
2813                    Some(Ordering::Equal)
2814                }
2815            }
2816            None => None,
2817        }
2818    }
2819}
2820
2821impl Default for ExactNum {
2822    fn default() -> ExactNum {
2823        ExactNum::new(DEFAULT_P)
2824    }
2825}
2826
2827#[cfg(feature = "std")]
2828impl FromStr for ExactNum {
2829    type Err = Error;
2830
2831    /// Returns parsed number or NAN in case of error.
2832    /// The implementation is not available in no_std environment.
2833    fn from_str(src: &str) -> Result<ExactNum, Self::Err> {
2834        let bf = crate::common::consts::TENPOWERS.with(|tp| {
2835            let cc = &mut tp.borrow_mut();
2836            ExactNum::parse(src, Radix::Dec, usize::MAX, RoundingMode::ToEven, cc)
2837        });
2838
2839        if bf.is_nan() {
2840            if let Some(err) = bf.err() {
2841                return Err(err);
2842            }
2843        }
2844
2845        Ok(bf)
2846    }
2847}
2848
2849macro_rules! impl_from {
2850    ($tt:ty, $fn:ident) => {
2851        impl From<$tt> for ExactNum {
2852            fn from(v: $tt) -> Self {
2853                ExactNum::$fn(v, DEFAULT_P)
2854            }
2855        }
2856    };
2857}
2858
2859impl_from!(i8, from_i8);
2860impl_from!(i16, from_i16);
2861impl_from!(i32, from_i32);
2862impl_from!(i64, from_i64);
2863impl_from!(i128, from_i128);
2864impl_from!(u8, from_u8);
2865impl_from!(u16, from_u16);
2866impl_from!(u32, from_u32);
2867impl_from!(u64, from_u64);
2868impl_from!(u128, from_u128);
2869
2870#[cfg(feature = "std")]
2871macro_rules! impl_format_rdx {
2872    ($trait:ty, $rdx:path) => {
2873        impl $trait for ExactNum {
2874            /// Formats the number.
2875            /// The implementation is not available in no_std environment.
2876            fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
2877                crate::common::consts::TENPOWERS.with(|tp| {
2878                    let cc = &mut tp.borrow_mut();
2879                    self.write_str(f, $rdx, RoundingMode::ToEven, cc)
2880                })
2881            }
2882        }
2883    };
2884}
2885
2886#[cfg(feature = "std")]
2887impl_format_rdx!(Binary, Radix::Bin);
2888#[cfg(feature = "std")]
2889impl_format_rdx!(Octal, Radix::Oct);
2890#[cfg(feature = "std")]
2891impl_format_rdx!(Display, Radix::Dec);
2892#[cfg(feature = "std")]
2893impl_format_rdx!(core::fmt::LowerExp, Radix::Dec);
2894#[cfg(feature = "std")]
2895impl_format_rdx!(UpperHex, Radix::Hex);
2896#[cfg(feature = "std")]
2897impl core::fmt::UpperExp for ExactNum {
2898    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2899        crate::common::consts::TENPOWERS.with(|tp| {
2900            let cc = &mut tp.borrow_mut();
2901            let mut s = String::new();
2902            self.write_str(&mut s, Radix::Dec, RoundingMode::ToEven, cc)?;
2903            f.write_str(&s.replace('e', "E"))
2904        })
2905    }
2906}
2907#[cfg(feature = "std")]
2908impl core::fmt::LowerHex for ExactNum {
2909    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2910        crate::common::consts::TENPOWERS.with(|tp| {
2911            let cc = &mut tp.borrow_mut();
2912            let mut s = String::new();
2913            self.write_str(&mut s, Radix::Hex, RoundingMode::ToEven, cc)?;
2914            if matches!(s.as_str(), "Inf" | "-Inf" | "NaN" | "Err") {
2915                f.write_str(&s)
2916            } else {
2917                f.write_str(&s.to_ascii_lowercase())
2918            }
2919        })
2920    }
2921}
2922
2923macro_rules! impl_exact_binop {
2924    ($trait:ident, $method:ident, $op:ident) => {
2925        impl core::ops::$trait<&ExactNum> for &ExactNum {
2926            type Output = ExactNum;
2927
2928            fn $method(self, rhs: &ExactNum) -> ExactNum {
2929                ExactNum::$op(self, rhs, DEFAULT_P, RoundingMode::ToEven)
2930            }
2931        }
2932
2933        impl core::ops::$trait<ExactNum> for &ExactNum {
2934            type Output = ExactNum;
2935
2936            fn $method(self, rhs: ExactNum) -> ExactNum {
2937                ExactNum::$op(self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2938            }
2939        }
2940
2941        impl core::ops::$trait<&ExactNum> for ExactNum {
2942            type Output = ExactNum;
2943
2944            fn $method(self, rhs: &ExactNum) -> ExactNum {
2945                ExactNum::$op(&self, rhs, DEFAULT_P, RoundingMode::ToEven)
2946            }
2947        }
2948
2949        impl core::ops::$trait<ExactNum> for ExactNum {
2950            type Output = ExactNum;
2951
2952            fn $method(self, rhs: ExactNum) -> ExactNum {
2953                ExactNum::$op(&self, &rhs, DEFAULT_P, RoundingMode::ToEven)
2954            }
2955        }
2956    };
2957}
2958
2959impl_exact_binop!(Add, add, add);
2960impl_exact_binop!(Sub, sub, sub);
2961impl_exact_binop!(Mul, mul, mul);
2962impl_exact_binop!(Div, div, div);
2963
2964/// A trait for conversion with additional arguments.
2965pub trait FromExt<T> {
2966    /// Converts `v` to ExactNum with precision `p` using rounding mode `rm`.
2967    fn from_ext(v: T, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self;
2968}
2969
2970impl<T> FromExt<T> for ExactNum
2971where
2972    ExactNum: From<T>,
2973{
2974    fn from_ext(v: T, p: usize, rm: RoundingMode, _cc: &mut Consts) -> Self {
2975        let mut ret = ExactNum::from(v);
2976        if let Err(err) = ret.set_precision(p, rm) {
2977            ExactNum::nan(Some(err))
2978        } else {
2979            ret
2980        }
2981    }
2982}
2983
2984impl FromExt<&str> for ExactNum {
2985    fn from_ext(v: &str, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
2986        ExactNum::parse(v, crate::Radix::Dec, p, rm, cc)
2987    }
2988}
2989
2990#[cfg(test)]
2991mod tests {
2992
2993    use crate::common::util::rand_p;
2994    use crate::defs::DEFAULT_P;
2995    use crate::ext::ONE;
2996    use crate::ext::TWO;
2997    use crate::Consts;
2998    use crate::Error;
2999    use crate::ExactNum;
3000    use crate::Radix;
3001    use crate::Sign;
3002    use crate::Word;
3003    use crate::INF_NEG;
3004    use crate::INF_POS;
3005    use crate::NAN;
3006    use crate::{defs::RoundingMode, WORD_BIT_SIZE};
3007
3008    use core::num::FpCategory;
3009    #[cfg(feature = "std")]
3010    use std::str::FromStr;
3011
3012    #[cfg(not(feature = "std"))]
3013    use alloc::format;
3014
3015    #[cfg(target_pointer_width = "32")]
3016    #[test]
3017    fn test_decimal_formatting_round_trip() {
3018        // Regression test: on 32-bit targets, decimal formatting must produce a string
3019        // that parses back to the original value without losing precision.
3020        let mut cc = Consts::new().unwrap();
3021        let p = 53;
3022        let rm = RoundingMode::ToEven;
3023        let value = ExactNum::parse("1.0", Radix::Dec, p, rm, &mut cc);
3024
3025        let formatted = value.format(Radix::Dec, rm, &mut cc).unwrap();
3026        assert_eq!(formatted, "1.e+0");
3027
3028        let reparsed = ExactNum::parse(&formatted, Radix::Dec, p, rm, &mut cc);
3029        assert_eq!(reparsed, value);
3030    }
3031
3032    #[test]
3033    fn test_ext() {
3034        let rm = RoundingMode::ToOdd;
3035        let mut cc = Consts::new().unwrap();
3036
3037        // Inf & NaN
3038        let d1 = ExactNum::from_u8(1, rand_p());
3039        assert!(!d1.is_inf());
3040        assert!(!d1.is_nan());
3041        assert!(!d1.is_inf_pos());
3042        assert!(!d1.is_inf_neg());
3043        assert!(d1.is_positive());
3044
3045        let mut d1 = d1.div(&ExactNum::new(rand_p()), rand_p(), rm);
3046        assert!(d1.is_inf());
3047        assert!(!d1.is_nan());
3048        assert!(d1.is_inf_pos());
3049        assert!(!d1.is_inf_neg());
3050        assert!(d1.is_positive());
3051
3052        d1.inv_sign();
3053        assert!(d1.is_inf());
3054        assert!(!d1.is_nan());
3055        assert!(!d1.is_inf_pos());
3056        assert!(d1.is_inf_neg());
3057        assert!(d1.is_negative());
3058
3059        let d1 = ExactNum::new(rand_p()).div(&ExactNum::new(rand_p()), rand_p(), rm);
3060        assert!(!d1.is_inf());
3061        assert!(d1.is_nan());
3062        assert!(!d1.is_inf_pos());
3063        assert!(!d1.is_inf_neg());
3064        assert!(d1.sign().is_none());
3065
3066        for _ in 0..1000 {
3067            let i = crate::common::test_rng::random::<i64>();
3068            let d1 = ExactNum::from_i64(i, rand_p());
3069            let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3070            assert!(d1.cmp(&n1) == Some(0));
3071
3072            let i = crate::common::test_rng::random::<u64>();
3073            let d1 = ExactNum::from_u64(i, rand_p());
3074            let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3075            assert!(d1.cmp(&n1) == Some(0));
3076
3077            let i = crate::common::test_rng::random::<i128>();
3078            let d1 = ExactNum::from_i128(i, rand_p());
3079            let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3080            assert!(d1.cmp(&n1) == Some(0));
3081
3082            let i = crate::common::test_rng::random::<u128>();
3083            let d1 = ExactNum::from_u128(i, rand_p());
3084            let n1 = ExactNum::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
3085            assert!(d1.cmp(&n1) == Some(0));
3086        }
3087
3088        assert!(ONE.exponent().is_some());
3089        assert!(INF_POS.exponent().is_none());
3090        assert!(INF_NEG.exponent().is_none());
3091        assert!(NAN.exponent().is_none());
3092
3093        assert!(ONE.as_raw_parts().is_some());
3094        assert!(INF_POS.as_raw_parts().is_none());
3095        assert!(INF_NEG.as_raw_parts().is_none());
3096        assert!(NAN.as_raw_parts().is_none());
3097
3098        assert!(ONE.add(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
3099        assert!(ONE.add(&INF_POS, rand_p(), rm).is_inf_pos());
3100        assert!(INF_POS.add(&ONE, rand_p(), rm).is_inf_pos());
3101        assert!(ONE.add(&INF_NEG, rand_p(), rm).is_inf_neg());
3102        assert!(INF_NEG.add(&ONE, rand_p(), rm).is_inf_neg());
3103        assert!(INF_POS.add(&INF_POS, rand_p(), rm).is_inf_pos());
3104        assert!(INF_POS.add(&INF_NEG, rand_p(), rm).is_nan());
3105        assert!(INF_NEG.add(&INF_NEG, rand_p(), rm).is_inf_neg());
3106        assert!(INF_NEG.add(&INF_POS, rand_p(), rm).is_nan());
3107
3108        assert!(ONE.add_full_prec(&ONE).cmp(&TWO) == Some(0));
3109        assert!(ONE.add_full_prec(&INF_POS).is_inf_pos());
3110        assert!(INF_POS.add_full_prec(&ONE).is_inf_pos());
3111        assert!(ONE.add_full_prec(&INF_NEG).is_inf_neg());
3112        assert!(INF_NEG.add_full_prec(&ONE).is_inf_neg());
3113        assert!(INF_POS.add_full_prec(&INF_POS).is_inf_pos());
3114        assert!(INF_POS.add_full_prec(&INF_NEG).is_nan());
3115        assert!(INF_NEG.add_full_prec(&INF_NEG).is_inf_neg());
3116        assert!(INF_NEG.add_full_prec(&INF_POS).is_nan());
3117
3118        assert!(ONE.sub_full_prec(&ONE).is_zero());
3119        assert!(ONE.sub_full_prec(&INF_POS).is_inf_neg());
3120        assert!(INF_POS.sub_full_prec(&ONE).is_inf_pos());
3121        assert!(ONE.sub_full_prec(&INF_NEG).is_inf_pos());
3122        assert!(INF_NEG.sub_full_prec(&ONE).is_inf_neg());
3123        assert!(INF_POS.sub_full_prec(&INF_POS).is_nan());
3124        assert!(INF_POS.sub_full_prec(&INF_NEG).is_inf_pos());
3125        assert!(INF_NEG.sub_full_prec(&INF_NEG).is_nan());
3126        assert!(INF_NEG.sub_full_prec(&INF_POS).is_inf_neg());
3127
3128        assert!(ONE.mul_full_prec(&ONE).cmp(&ONE) == Some(0));
3129        assert!(ONE.mul_full_prec(&INF_POS).is_inf_pos());
3130        assert!(INF_POS.mul_full_prec(&ONE).is_inf_pos());
3131        assert!(ONE.mul_full_prec(&INF_NEG).is_inf_neg());
3132        assert!(INF_NEG.mul_full_prec(&ONE).is_inf_neg());
3133        assert!(INF_POS.mul_full_prec(&INF_POS).is_inf_pos());
3134        assert!(INF_POS.mul_full_prec(&INF_NEG).is_inf_neg());
3135        assert!(INF_NEG.mul_full_prec(&INF_NEG).is_inf_pos());
3136        assert!(INF_NEG.mul_full_prec(&INF_POS).is_inf_neg());
3137
3138        assert!(TWO.sub(&ONE, rand_p(), rm).cmp(&ONE) == Some(0));
3139        assert!(ONE.sub(&INF_POS, rand_p(), rm).is_inf_neg());
3140        assert!(INF_POS.sub(&ONE, rand_p(), rm).is_inf_pos());
3141        assert!(ONE.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
3142        assert!(INF_NEG.sub(&ONE, rand_p(), rm).is_inf_neg());
3143        assert!(INF_POS.sub(&INF_POS, rand_p(), rm).is_nan());
3144        assert!(INF_POS.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
3145        assert!(INF_NEG.sub(&INF_NEG, rand_p(), rm).is_nan());
3146        assert!(INF_NEG.sub(&INF_POS, rand_p(), rm).is_inf_neg());
3147
3148        assert!(TWO.mul(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
3149        assert!(ONE.mul(&INF_POS, rand_p(), rm).is_inf_pos());
3150        assert!(INF_POS.mul(&ONE, rand_p(), rm).is_inf_pos());
3151        assert!(ONE.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
3152        assert!(INF_NEG.mul(&ONE, rand_p(), rm).is_inf_neg());
3153        assert!(ONE.neg().mul(&INF_POS, rand_p(), rm).is_inf_neg());
3154        assert!(ONE.neg().mul(&INF_NEG, rand_p(), rm).is_inf_pos());
3155        assert!(INF_POS.mul(&ONE.neg(), rand_p(), rm).is_inf_neg());
3156        assert!(INF_NEG.mul(&ONE.neg(), rand_p(), rm).is_inf_pos());
3157        assert!(INF_POS.mul(&INF_POS, rand_p(), rm).is_inf_pos());
3158        assert!(INF_POS.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
3159        assert!(INF_NEG.mul(&INF_NEG, rand_p(), rm).is_inf_pos());
3160        assert!(INF_NEG.mul(&INF_POS, rand_p(), rm).is_inf_neg());
3161        assert!(INF_POS.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
3162        assert!(INF_NEG.mul(&ExactNum::new(rand_p()), rand_p(), rm).is_nan());
3163        assert!(ExactNum::new(rand_p()).mul(&INF_POS, rand_p(), rm).is_nan());
3164        assert!(ExactNum::new(rand_p()).mul(&INF_NEG, rand_p(), rm).is_nan());
3165
3166        assert!(TWO.div(&TWO, rand_p(), rm).cmp(&ONE) == Some(0));
3167        assert!(TWO.div(&INF_POS, rand_p(), rm).is_zero());
3168        assert!(INF_POS.div(&TWO, rand_p(), rm).is_inf_pos());
3169        assert!(TWO.div(&INF_NEG, rand_p(), rm).is_zero());
3170        assert!(INF_NEG.div(&TWO, rand_p(), rm).is_inf_neg());
3171        assert!(TWO.neg().div(&INF_POS, rand_p(), rm).is_zero());
3172        assert!(TWO.neg().div(&INF_NEG, rand_p(), rm).is_zero());
3173        assert!(INF_POS.div(&TWO.neg(), rand_p(), rm).is_inf_neg());
3174        assert!(INF_NEG.div(&TWO.neg(), rand_p(), rm).is_inf_pos());
3175        assert!(INF_POS.div(&INF_POS, rand_p(), rm).is_nan());
3176        assert!(INF_POS.div(&INF_NEG, rand_p(), rm).is_nan());
3177        assert!(INF_NEG.div(&INF_NEG, rand_p(), rm).is_nan());
3178        assert!(INF_NEG.div(&INF_POS, rand_p(), rm).is_nan());
3179        assert!(INF_POS
3180            .div(&ExactNum::new(rand_p()), rand_p(), rm)
3181            .is_inf_pos());
3182        assert!(INF_NEG
3183            .div(&ExactNum::new(rand_p()), rand_p(), rm)
3184            .is_inf_neg());
3185        assert!(ExactNum::new(rand_p())
3186            .div(&INF_POS, rand_p(), rm)
3187            .is_zero());
3188        assert!(ExactNum::new(rand_p())
3189            .div(&INF_NEG, rand_p(), rm)
3190            .is_zero());
3191
3192        assert!(TWO.rem(&TWO).is_zero());
3193        assert!(TWO.rem(&INF_POS).cmp(&TWO) == Some(0));
3194        assert!(INF_POS.rem(&TWO).is_nan());
3195        assert!(TWO.rem(&INF_NEG).cmp(&TWO) == Some(0));
3196        assert!(INF_NEG.rem(&TWO).is_nan());
3197        assert!(TWO.neg().rem(&INF_POS).cmp(&TWO.neg()) == Some(0));
3198        assert!(TWO.neg().rem(&INF_NEG).cmp(&TWO.neg()) == Some(0));
3199        assert!(INF_POS.rem(&TWO.neg()).is_nan());
3200        assert!(INF_NEG.rem(&TWO.neg()).is_nan());
3201        assert!(INF_POS.rem(&INF_POS).is_nan());
3202        assert!(INF_POS.rem(&INF_NEG).is_nan());
3203        assert!(INF_NEG.rem(&INF_NEG).is_nan());
3204        assert!(INF_NEG.rem(&INF_POS).is_nan());
3205        assert!(INF_POS.rem(&ExactNum::new(rand_p())).is_nan());
3206        assert!(INF_NEG.rem(&ExactNum::new(rand_p())).is_nan());
3207        assert!(ExactNum::new(rand_p()).rem(&INF_POS).is_zero());
3208        assert!(ExactNum::new(rand_p()).rem(&INF_NEG).is_zero());
3209
3210        for op in [ExactNum::add, ExactNum::sub, ExactNum::mul, ExactNum::div] {
3211            assert!(op(&NAN, &ONE, rand_p(), rm).is_nan());
3212            assert!(op(&ONE, &NAN, rand_p(), rm).is_nan());
3213            assert!(op(&NAN, &INF_POS, rand_p(), rm).is_nan());
3214            assert!(op(&INF_POS, &NAN, rand_p(), rm).is_nan());
3215            assert!(op(&NAN, &INF_NEG, rand_p(), rm).is_nan());
3216            assert!(op(&INF_NEG, &NAN, rand_p(), rm).is_nan());
3217            assert!(op(&NAN, &NAN, rand_p(), rm).is_nan());
3218        }
3219
3220        assert!(ExactNum::rem(&NAN, &ONE).is_nan());
3221        assert!(ExactNum::rem(&ONE, &NAN).is_nan());
3222        assert!(ExactNum::rem(&NAN, &INF_POS).is_nan());
3223        assert!(ExactNum::rem(&INF_POS, &NAN).is_nan());
3224        assert!(ExactNum::rem(&NAN, &INF_NEG).is_nan());
3225        assert!(ExactNum::rem(&INF_NEG, &NAN).is_nan());
3226        assert!(ExactNum::rem(&NAN, &NAN).is_nan());
3227
3228        for op in [ExactNum::add_full_prec, ExactNum::sub_full_prec, ExactNum::mul_full_prec] {
3229            assert!(op(&NAN, &ONE).is_nan());
3230            assert!(op(&ONE, &NAN).is_nan());
3231            assert!(op(&NAN, &INF_POS).is_nan());
3232            assert!(op(&INF_POS, &NAN).is_nan());
3233            assert!(op(&NAN, &INF_NEG).is_nan());
3234            assert!(op(&INF_NEG, &NAN).is_nan());
3235            assert!(op(&NAN, &NAN).is_nan());
3236        }
3237
3238        assert!(ONE.cmp(&ONE).unwrap() == 0);
3239        assert!(ONE.cmp(&INF_POS).unwrap() < 0);
3240        assert!(INF_POS.cmp(&ONE).unwrap() > 0);
3241        assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3242        assert!(ONE.cmp(&INF_NEG).unwrap() > 0);
3243        assert!(INF_NEG.cmp(&ONE).unwrap() < 0);
3244        assert!(INF_NEG.cmp(&INF_NEG).unwrap() == 0);
3245        assert!(INF_POS.cmp(&INF_NEG).unwrap() > 0);
3246        assert!(INF_NEG.cmp(&INF_POS).unwrap() < 0);
3247        assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
3248        assert!(ONE.cmp(&NAN).is_none());
3249        assert!(NAN.cmp(&ONE).is_none());
3250        assert!(INF_POS.cmp(&NAN).is_none());
3251        assert!(NAN.cmp(&INF_POS).is_none());
3252        assert!(INF_NEG.cmp(&NAN).is_none());
3253        assert!(NAN.cmp(&INF_NEG).is_none());
3254        assert!(NAN.cmp(&NAN).is_none());
3255
3256        assert!(ONE.abs_cmp(&ONE).unwrap() == 0);
3257        assert!(ONE.abs_cmp(&INF_POS).unwrap() < 0);
3258        assert!(INF_POS.abs_cmp(&ONE).unwrap() > 0);
3259        assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3260        assert!(ONE.abs_cmp(&INF_NEG).unwrap() < 0);
3261        assert!(INF_NEG.abs_cmp(&ONE).unwrap() > 0);
3262        assert!(INF_NEG.abs_cmp(&INF_NEG).unwrap() == 0);
3263        assert!(INF_POS.abs_cmp(&INF_NEG).unwrap() == 0);
3264        assert!(INF_NEG.abs_cmp(&INF_POS).unwrap() == 0);
3265        assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
3266        assert!(ONE.abs_cmp(&NAN).is_none());
3267        assert!(NAN.abs_cmp(&ONE).is_none());
3268        assert!(INF_POS.abs_cmp(&NAN).is_none());
3269        assert!(NAN.abs_cmp(&INF_POS).is_none());
3270        assert!(INF_NEG.abs_cmp(&NAN).is_none());
3271        assert!(NAN.abs_cmp(&INF_NEG).is_none());
3272        assert!(NAN.abs_cmp(&NAN).is_none());
3273
3274        assert!(ONE.is_positive());
3275        assert!(!ONE.is_negative());
3276
3277        assert!(ONE.neg().is_negative());
3278        assert!(!ONE.neg().is_positive());
3279        assert!(!INF_POS.is_negative());
3280        assert!(INF_POS.is_positive());
3281        assert!(INF_NEG.is_negative());
3282        assert!(!INF_NEG.is_positive());
3283        assert!(!NAN.is_positive());
3284        assert!(!NAN.is_negative());
3285
3286        assert!(ONE.pow(&ONE, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3287        assert!(ExactNum::new(DEFAULT_P)
3288            .pow(&INF_POS, rand_p(), rm, &mut cc)
3289            .is_zero());
3290        assert!(ExactNum::new(DEFAULT_P)
3291            .pow(&INF_NEG, rand_p(), rm, &mut cc)
3292            .is_zero());
3293        assert!(ONE.pow(&INF_POS, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3294        assert!(ONE.pow(&INF_NEG, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3295        assert!(TWO.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3296        assert!(TWO.pow(&INF_NEG, rand_p(), rm, &mut cc).is_inf_neg());
3297        assert!(INF_POS.pow(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3298        assert!(INF_NEG.pow(&ONE, rand_p(), rm, &mut cc).is_inf_neg());
3299        assert!(INF_NEG.pow(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3300        assert!(INF_POS.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3301        assert!(INF_NEG.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
3302        assert!(
3303            INF_POS
3304                .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3305                .cmp(&ONE)
3306                == Some(0)
3307        );
3308        assert!(
3309            INF_NEG
3310                .pow(&ExactNum::new(DEFAULT_P), rand_p(), rm, &mut cc)
3311                .cmp(&ONE)
3312                == Some(0)
3313        );
3314        assert!(INF_POS.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3315        assert!(INF_NEG.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3316        assert!(INF_POS.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3317        assert!(INF_NEG.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
3318
3319        let half = ONE.div(&TWO, rand_p(), rm);
3320        assert!(TWO.log(&TWO, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3321        assert!(TWO.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3322        assert!(TWO.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3323        assert!(INF_POS.log(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
3324        assert!(INF_NEG.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3325        assert!(half.log(&half, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3326        assert!(half.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
3327        assert!(half.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3328        assert!(INF_POS.log(&half, rand_p(), rm, &mut cc).is_inf_neg());
3329        assert!(INF_NEG.log(&half, rand_p(), rm, &mut cc).is_nan());
3330        assert!(INF_POS.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3331        assert!(INF_POS.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3332        assert!(INF_NEG.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3333        assert!(INF_NEG.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3334        assert!(TWO.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3335        assert!(half.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
3336        assert!(ONE.log(&ONE, rand_p(), rm, &mut cc).is_nan());
3337
3338        assert!(ONE.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3339        assert!(NAN.pow(&ONE, rand_p(), rm, &mut cc).is_nan());
3340        assert!(INF_POS.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3341        assert!(NAN.pow(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3342        assert!(INF_NEG.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3343        assert!(NAN.pow(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3344        assert!(NAN.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
3345
3346        assert!(NAN.powi(2, rand_p(), rm).is_nan());
3347        assert!(NAN.powi(0, rand_p(), rm).is_nan());
3348        assert!(INF_POS.powi(2, rand_p(), rm).is_inf_pos());
3349        assert!(INF_POS.powi(3, rand_p(), rm).is_inf_pos());
3350        assert!(INF_NEG.powi(4, rand_p(), rm).is_inf_pos());
3351        assert!(INF_NEG.powi(5, rand_p(), rm).is_inf_neg());
3352        assert!(INF_POS.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3353        assert!(INF_NEG.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
3354
3355        assert!(TWO.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3356        assert!(NAN.log(&TWO, rand_p(), rm, &mut cc).is_nan());
3357        assert!(INF_POS.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3358        assert!(NAN.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
3359        assert!(INF_NEG.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3360        assert!(NAN.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3361        assert!(NAN.log(&NAN, rand_p(), rm, &mut cc).is_nan());
3362
3363        assert!(INF_NEG.abs().is_inf_pos());
3364        assert!(INF_POS.abs().is_inf_pos());
3365        assert!(NAN.abs().is_nan());
3366
3367        assert!(INF_NEG.int().is_nan());
3368        assert!(INF_POS.int().is_nan());
3369        assert!(NAN.int().is_nan());
3370
3371        assert!(INF_NEG.fract().is_nan());
3372        assert!(INF_POS.fract().is_nan());
3373        assert!(NAN.fract().is_nan());
3374
3375        assert!(INF_NEG.ceil().is_inf_neg());
3376        assert!(INF_POS.ceil().is_inf_pos());
3377        assert!(NAN.ceil().is_nan());
3378
3379        assert!(INF_NEG.floor().is_inf_neg());
3380        assert!(INF_POS.floor().is_inf_pos());
3381        assert!(NAN.floor().is_nan());
3382
3383        for rm in [
3384            RoundingMode::Up,
3385            RoundingMode::Down,
3386            RoundingMode::ToZero,
3387            RoundingMode::FromZero,
3388            RoundingMode::ToEven,
3389            RoundingMode::ToOdd,
3390        ] {
3391            assert!(INF_NEG.round(0, rm).is_inf_neg());
3392            assert!(INF_POS.round(0, rm).is_inf_pos());
3393            assert!(NAN.round(0, rm).is_nan());
3394        }
3395
3396        assert!(INF_NEG.sqrt(rand_p(), rm).is_nan());
3397        assert!(INF_POS.sqrt(rand_p(), rm).is_inf_pos());
3398        assert!(NAN.sqrt(rand_p(), rm).is_nan());
3399
3400        assert!(INF_NEG.cbrt(rand_p(), rm).is_inf_neg());
3401        assert!(INF_POS.cbrt(rand_p(), rm).is_inf_pos());
3402        assert!(NAN.cbrt(rand_p(), rm).is_nan());
3403
3404        for op in [ExactNum::ln, ExactNum::log2, ExactNum::log10] {
3405            assert!(op(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
3406            assert!(op(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
3407            assert!(op(&NAN, rand_p(), rm, &mut cc).is_nan());
3408        }
3409
3410        assert!(INF_NEG.exp(rand_p(), rm, &mut cc).is_zero());
3411        assert!(INF_POS.exp(rand_p(), rm, &mut cc).is_inf_pos());
3412        assert!(NAN.exp(rand_p(), rm, &mut cc).is_nan());
3413
3414        assert!(INF_NEG.sin(rand_p(), rm, &mut cc).is_nan());
3415        assert!(INF_POS.sin(rand_p(), rm, &mut cc).is_nan());
3416        assert!(NAN.sin(rand_p(), rm, &mut cc).is_nan());
3417
3418        assert!(INF_NEG.cos(rand_p(), rm, &mut cc).is_nan());
3419        assert!(INF_POS.cos(rand_p(), rm, &mut cc).is_nan());
3420        assert!(NAN.cos(rand_p(), rm, &mut cc).is_nan());
3421
3422        assert!(INF_NEG.tan(rand_p(), rm, &mut cc).is_nan());
3423        assert!(INF_POS.tan(rand_p(), rm, &mut cc).is_nan());
3424        assert!(NAN.tan(rand_p(), rm, &mut cc).is_nan());
3425
3426        assert!(INF_NEG.asin(rand_p(), rm, &mut cc).is_nan());
3427        assert!(INF_POS.asin(rand_p(), rm, &mut cc).is_nan());
3428        assert!(NAN.asin(rand_p(), rm, &mut cc).is_nan());
3429
3430        assert!(INF_NEG.acos(rand_p(), rm, &mut cc).is_nan());
3431        assert!(INF_POS.acos(rand_p(), rm, &mut cc).is_nan());
3432        assert!(NAN.acos(rand_p(), rm, &mut cc).is_nan());
3433
3434        let p = rand_p();
3435        let mut half_pi: ExactNum = cc.pi_num(p, rm).unwrap().into();
3436        half_pi.set_exponent(1);
3437        assert!(INF_NEG.atan(p, rm, &mut cc).cmp(&half_pi.neg()) == Some(0));
3438        assert!(INF_POS.atan(p, rm, &mut cc).cmp(&half_pi) == Some(0));
3439        assert!(NAN.atan(rand_p(), rm, &mut cc).is_nan());
3440
3441        assert!(INF_NEG.sinh(rand_p(), rm, &mut cc).is_inf_neg());
3442        assert!(INF_POS.sinh(rand_p(), rm, &mut cc).is_inf_pos());
3443        assert!(NAN.sinh(rand_p(), rm, &mut cc).is_nan());
3444
3445        assert!(INF_NEG.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3446        assert!(INF_POS.cosh(rand_p(), rm, &mut cc).is_inf_pos());
3447        assert!(NAN.cosh(rand_p(), rm, &mut cc).is_nan());
3448
3449        assert!(INF_NEG.tanh(rand_p(), rm, &mut cc).cmp(&ONE.neg()) == Some(0));
3450        assert!(INF_POS.tanh(rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
3451        assert!(NAN.tanh(rand_p(), rm, &mut cc).is_nan());
3452
3453        assert!(INF_NEG.asinh(rand_p(), rm, &mut cc).is_inf_neg());
3454        assert!(INF_POS.asinh(rand_p(), rm, &mut cc).is_inf_pos());
3455        assert!(NAN.asinh(rand_p(), rm, &mut cc).is_nan());
3456
3457        assert!(INF_NEG.acosh(rand_p(), rm, &mut cc).is_nan());
3458        assert!(INF_POS.acosh(rand_p(), rm, &mut cc).is_inf_pos());
3459        assert!(NAN.acosh(rand_p(), rm, &mut cc).is_nan());
3460
3461        assert!(INF_NEG.atanh(rand_p(), rm, &mut cc).is_nan());
3462        assert!(INF_POS.atanh(rand_p(), rm, &mut cc).is_nan());
3463        assert!(NAN.atanh(rand_p(), rm, &mut cc).is_nan());
3464
3465        assert!(INF_NEG.reciprocal(rand_p(), rm).is_zero());
3466        assert!(INF_POS.reciprocal(rand_p(), rm).is_zero());
3467        assert!(NAN.reciprocal(rand_p(), rm).is_nan());
3468
3469        assert!(TWO.signum().cmp(&ONE) == Some(0));
3470        assert!(TWO.neg().signum().cmp(&ONE.neg()) == Some(0));
3471        assert!(INF_POS.signum().cmp(&ONE) == Some(0));
3472        assert!(INF_NEG.signum().cmp(&ONE.neg()) == Some(0));
3473        assert!(NAN.signum().is_nan());
3474
3475        let d1 = ONE.clone();
3476        assert!(d1.exponent() == Some(1));
3477        let words: &[Word] = {
3478            #[cfg(not(target_pointer_width = "32"))]
3479            {
3480                &[0, 0x8000000000000000]
3481            }
3482            #[cfg(target_pointer_width = "32")]
3483            {
3484                &[0, 0, 0, 0x80000000]
3485            }
3486        };
3487
3488        assert!(d1.mantissa_digits() == Some(words));
3489        assert!(d1.is_inline());
3490        assert!(d1.mantissa_max_bit_len() == Some(DEFAULT_P));
3491        assert!(d1.precision() == Some(DEFAULT_P));
3492        assert!(d1.sign() == Some(Sign::Pos));
3493
3494        assert!(INF_POS.exponent().is_none());
3495        assert!(INF_POS.mantissa_digits().is_none());
3496        assert!(INF_POS.mantissa_max_bit_len().is_none());
3497        assert!(INF_POS.precision().is_none());
3498        assert!(INF_POS.sign() == Some(Sign::Pos));
3499
3500        assert!(INF_NEG.exponent().is_none());
3501        assert!(INF_NEG.mantissa_digits().is_none());
3502        assert!(INF_NEG.mantissa_max_bit_len().is_none());
3503        assert!(INF_NEG.precision().is_none());
3504        assert!(INF_NEG.sign() == Some(Sign::Neg));
3505
3506        assert!(NAN.exponent().is_none());
3507        assert!(NAN.mantissa_digits().is_none());
3508        assert!(NAN.mantissa_max_bit_len().is_none());
3509        assert!(NAN.precision().is_none());
3510        assert!(NAN.sign().is_none());
3511
3512        INF_POS.clone().set_exponent(1);
3513        INF_POS.clone().set_precision(1, rm).unwrap();
3514        INF_POS.clone().set_sign(Sign::Pos);
3515
3516        INF_NEG.clone().set_exponent(1);
3517        INF_NEG.clone().set_precision(1, rm).unwrap();
3518        INF_NEG.clone().set_sign(Sign::Pos);
3519
3520        NAN.clone().set_exponent(1);
3521        NAN.clone().set_precision(1, rm).unwrap();
3522        NAN.clone().set_sign(Sign::Pos);
3523
3524        assert!(INF_POS.min(&ONE).cmp(&ONE) == Some(0));
3525        assert!(INF_NEG.min(&ONE).is_inf_neg());
3526        assert!(NAN.min(&ONE).is_nan());
3527        assert!(ONE.min(&INF_POS).cmp(&ONE) == Some(0));
3528        assert!(ONE.min(&INF_NEG).is_inf_neg());
3529        assert!(ONE.min(&NAN).is_nan());
3530        assert!(NAN.min(&INF_POS).is_nan());
3531        assert!(NAN.min(&INF_NEG).is_nan());
3532        assert!(NAN.min(&NAN).is_nan());
3533        assert!(INF_NEG.min(&INF_POS).is_inf_neg());
3534        assert!(INF_POS.min(&INF_NEG).is_inf_neg());
3535        assert!(INF_POS.min(&INF_POS).is_inf_pos());
3536        assert!(INF_NEG.min(&INF_NEG).is_inf_neg());
3537
3538        assert!(INF_POS.max(&ONE).is_inf_pos());
3539        assert!(INF_NEG.max(&ONE).cmp(&ONE) == Some(0));
3540        assert!(NAN.max(&ONE).is_nan());
3541        assert!(ONE.max(&INF_POS).is_inf_pos());
3542        assert!(ONE.max(&INF_NEG).cmp(&ONE) == Some(0));
3543        assert!(ONE.max(&NAN).is_nan());
3544        assert!(NAN.max(&INF_POS).is_nan());
3545        assert!(NAN.max(&INF_NEG).is_nan());
3546        assert!(NAN.max(&NAN).is_nan());
3547        assert!(INF_NEG.max(&INF_POS).is_inf_pos());
3548        assert!(INF_POS.max(&INF_NEG).is_inf_pos());
3549        assert!(INF_POS.max(&INF_POS).is_inf_pos());
3550        assert!(INF_NEG.max(&INF_NEG).is_inf_neg());
3551
3552        assert!(ONE.clamp(&ONE.neg(), &TWO).cmp(&ONE) == Some(0));
3553        assert!(ONE.clamp(&TWO, &ONE).is_nan());
3554        assert!(ONE.clamp(&INF_POS, &ONE).is_nan());
3555        assert!(ONE.clamp(&TWO, &INF_NEG).is_nan());
3556        assert!(ONE.neg().clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3557        assert!(TWO.clamp(&ONE.neg(), &ONE).cmp(&ONE) == Some(0));
3558        assert!(INF_POS.clamp(&ONE, &TWO).cmp(&TWO) == Some(0));
3559        assert!(INF_POS.clamp(&ONE, &INF_POS).is_inf_pos());
3560        assert!(INF_POS.clamp(&INF_NEG, &ONE).cmp(&ONE) == Some(0));
3561        assert!(INF_POS.clamp(&NAN, &INF_POS).is_nan());
3562        assert!(INF_POS.clamp(&ONE, &NAN).is_nan());
3563        assert!(INF_POS.clamp(&NAN, &NAN).is_nan());
3564        assert!(INF_NEG.clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
3565        assert!(INF_NEG.clamp(&ONE, &INF_POS).cmp(&ONE) == Some(0));
3566        assert!(INF_NEG.clamp(&INF_NEG, &ONE).is_inf_neg());
3567        assert!(INF_NEG.clamp(&NAN, &INF_POS).is_nan());
3568        assert!(INF_NEG.clamp(&ONE, &NAN).is_nan());
3569        assert!(INF_NEG.clamp(&NAN, &NAN).is_nan());
3570        assert!(NAN.clamp(&ONE, &TWO).is_nan());
3571        assert!(NAN.clamp(&NAN, &TWO).is_nan());
3572        assert!(NAN.clamp(&ONE, &NAN).is_nan());
3573        assert!(NAN.clamp(&NAN, &NAN).is_nan());
3574        assert!(NAN.clamp(&INF_NEG, &INF_POS).is_nan());
3575
3576        assert!(ExactNum::min_positive(DEFAULT_P).classify() == FpCategory::Subnormal);
3577        assert!(INF_POS.classify() == FpCategory::Infinite);
3578        assert!(INF_NEG.classify() == FpCategory::Infinite);
3579        assert!(NAN.classify() == FpCategory::Nan);
3580        assert!(ONE.classify() == FpCategory::Normal);
3581
3582        assert!(!INF_POS.is_subnormal());
3583        assert!(!INF_NEG.is_subnormal());
3584        assert!(!NAN.is_subnormal());
3585        assert!(ExactNum::min_positive(DEFAULT_P).is_subnormal());
3586        assert!(!ExactNum::min_positive_normal(DEFAULT_P).is_subnormal());
3587        assert!(!ExactNum::max_value(DEFAULT_P).is_subnormal());
3588        assert!(!ExactNum::min_value(DEFAULT_P).is_subnormal());
3589
3590        let n1 = ExactNum::convert_from_radix(
3591            Sign::Pos,
3592            &[],
3593            0,
3594            Radix::Dec,
3595            usize::MAX - 1,
3596            RoundingMode::None,
3597            &mut cc,
3598        );
3599        assert!(n1.is_nan());
3600        assert!(n1.err() == Some(Error::InvalidArgument));
3601
3602        assert!(
3603            n1.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3604                == Err(Error::InvalidArgument)
3605        );
3606        assert!(
3607            INF_POS.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3608                == Err(Error::InvalidArgument)
3609        );
3610        assert!(
3611            INF_NEG.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
3612                == Err(Error::InvalidArgument)
3613        );
3614    }
3615
3616    #[cfg(feature = "std")]
3617    #[test]
3618    fn test_ops_std() {
3619        let mut cc = Consts::new().unwrap();
3620
3621        let d1 = ExactNum::parse(
3622            "0.0123456789012345678901234567890123456789",
3623            Radix::Dec,
3624            DEFAULT_P,
3625            RoundingMode::None,
3626            &mut cc,
3627        );
3628
3629        let d1str = format!("{}", d1);
3630        assert_eq!(&d1str, "1.23456789012345678901234567890123456789e-2");
3631        assert_eq!(format!("{:e}", d1), d1str);
3632        assert_eq!(
3633            format!("{:E}", d1),
3634            "1.23456789012345678901234567890123456789E-2"
3635        );
3636        let mut d2 = ExactNum::from_str(&d1str).unwrap();
3637        d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3638        assert_eq!(d2, d1);
3639
3640        let d1 = ExactNum::parse(
3641            "-123.456789012345678901234567890123456789",
3642            Radix::Dec,
3643            DEFAULT_P,
3644            RoundingMode::None,
3645            &mut cc,
3646        );
3647        let d1str = format!("{}", d1);
3648        assert_eq!(&d1str, "-1.23456789012345678901234567890123456789e+2");
3649        let mut d2 = ExactNum::from_str(&d1str).unwrap();
3650        d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
3651        assert_eq!(d2, d1);
3652
3653        let d1str = format!("{}", INF_POS);
3654        assert_eq!(d1str, "Inf");
3655
3656        let d1str = format!("{}", INF_NEG);
3657        assert_eq!(d1str, "-Inf");
3658
3659        let d1str = format!("{}", NAN);
3660        assert_eq!(d1str, "NaN");
3661
3662        assert!(ExactNum::from_str("abc").is_ok());
3663        assert!(ExactNum::from_str("abc").unwrap().is_nan());
3664    }
3665
3666    #[test]
3667    pub fn test_ops() {
3668        let mut cc = Consts::new().unwrap();
3669
3670        let d1 = -&(TWO.clone());
3671        assert!(d1.is_negative());
3672
3673        let p = DEFAULT_P;
3674        let rm = RoundingMode::ToEven;
3675        let two = ExactNum::from_u8(2, p);
3676        let eighth = two.powsi(-3, p, rm);
3677        let expected = ExactNum::from_u8(1, p).div(&ExactNum::from_u8(8, p), p, rm);
3678        assert_eq!(eighth.cmp(&expected), Some(0));
3679        assert_eq!(two.powsi(3, p, rm).cmp(&ExactNum::from_u8(8, p)), Some(0));
3680        assert!(
3681            ExactNum::from_i8(-123, p) == ExactNum::parse("-1.23e+2", Radix::Dec, p, rm, &mut cc)
3682        );
3683        assert!(
3684            ExactNum::from_u8(123, p) == ExactNum::parse("1.23e+2", Radix::Dec, p, rm, &mut cc)
3685        );
3686        assert!(
3687            ExactNum::from_i16(-12312, p)
3688                == ExactNum::parse("-1.2312e+4", Radix::Dec, p, rm, &mut cc)
3689        );
3690        assert!(
3691            ExactNum::from_u16(12312, p)
3692                == ExactNum::parse("1.2312e+4", Radix::Dec, p, rm, &mut cc)
3693        );
3694        assert!(
3695            ExactNum::from_i32(-123456789, p)
3696                == ExactNum::parse("-1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3697        );
3698        assert!(
3699            ExactNum::from_u32(123456789, p)
3700                == ExactNum::parse("1.23456789e+8", Radix::Dec, p, rm, &mut cc)
3701        );
3702        assert!(
3703            ExactNum::from_i64(-1234567890123456789, p)
3704                == ExactNum::parse("-1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3705        );
3706        assert!(
3707            ExactNum::from_u64(1234567890123456789, p)
3708                == ExactNum::parse("1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
3709        );
3710        assert!(
3711            ExactNum::from_i128(-123456789012345678901234567890123456789, p)
3712                == ExactNum::parse(
3713                    "-1.23456789012345678901234567890123456789e+38",
3714                    Radix::Dec,
3715                    p,
3716                    rm,
3717                    &mut cc
3718                )
3719        );
3720        assert!(
3721            ExactNum::from_u128(123456789012345678901234567890123456789, p)
3722                == ExactNum::parse(
3723                    "1.23456789012345678901234567890123456789e+38",
3724                    Radix::Dec,
3725                    p,
3726                    rm,
3727                    &mut cc
3728                )
3729        );
3730
3731        let neg = ExactNum::from_i8(-3, WORD_BIT_SIZE);
3732        let pos = ExactNum::from_i8(5, WORD_BIT_SIZE);
3733
3734        assert!(pos > neg);
3735        assert!(neg < pos);
3736        assert!(!(pos < neg));
3737        assert!(!(neg > pos));
3738        assert!(INF_NEG < neg);
3739        assert!(INF_NEG < pos);
3740        assert!(INF_NEG < INF_POS);
3741        assert!(!(INF_NEG > neg));
3742        assert!(!(INF_NEG > pos));
3743        assert!(!(INF_NEG > INF_POS));
3744        assert!(INF_POS > neg);
3745        assert!(INF_POS > pos);
3746        assert!(INF_POS > INF_NEG);
3747        assert!(!(INF_POS < neg));
3748        assert!(!(INF_POS < pos));
3749        assert!(!(INF_POS < INF_NEG));
3750        assert!(!(INF_POS > INF_POS));
3751        assert!(!(INF_POS < INF_POS));
3752        assert!(!(INF_NEG > INF_NEG));
3753        assert!(!(INF_NEG < INF_NEG));
3754        assert!(!(INF_POS > NAN));
3755        assert!(!(INF_POS < NAN));
3756        assert!(!(INF_NEG > NAN));
3757        assert!(!(INF_NEG < NAN));
3758        assert!(!(NAN > INF_POS));
3759        assert!(!(NAN < INF_POS));
3760        assert!(!(NAN > INF_NEG));
3761        assert!(!(NAN < INF_NEG));
3762        assert!(!(NAN > NAN));
3763        assert!(!(NAN < NAN));
3764        assert!(!(neg > NAN));
3765        assert!(!(neg < NAN));
3766        assert!(!(pos > NAN));
3767        assert!(!(pos < NAN));
3768        assert!(!(NAN > neg));
3769        assert!(!(NAN < neg));
3770        assert!(!(NAN > pos));
3771        assert!(!(NAN < pos));
3772
3773        assert!(!(NAN == NAN));
3774        assert!(!(NAN == INF_POS));
3775        assert!(!(NAN == INF_NEG));
3776        assert!(!(INF_POS == NAN));
3777        assert!(!(INF_NEG == NAN));
3778        assert!(!(INF_NEG == INF_POS));
3779        assert!(!(INF_POS == INF_NEG));
3780        assert!(!(INF_POS == neg));
3781        assert!(!(INF_POS == pos));
3782        assert!(!(INF_NEG == neg));
3783        assert!(!(INF_NEG == pos));
3784        assert!(!(neg == INF_POS));
3785        assert!(!(pos == INF_POS));
3786        assert!(!(neg == INF_NEG));
3787        assert!(!(pos == INF_NEG));
3788        assert!(!(pos == neg));
3789        assert!(!(neg == pos));
3790        assert!(neg == neg);
3791        assert!(pos == pos);
3792        assert!(INF_NEG == INF_NEG);
3793        assert!(INF_POS == INF_POS);
3794    }
3795
3796    #[test]
3797    fn test_oom_and_large_precision() {
3798        let oom = ExactNum::nan(Some(Error::MemoryAllocation));
3799        assert!(oom.is_nan());
3800        assert_eq!(oom.err(), Some(Error::MemoryAllocation));
3801
3802        let n = ExactNum::new(usize::MAX);
3803        assert!(n.is_nan());
3804        assert_eq!(n.err(), Some(Error::InvalidArgument));
3805
3806        let p = 128 * WORD_BIT_SIZE;
3807        let a = ExactNum::from_word(3, p);
3808        let b = ExactNum::from_word(5, p);
3809        let s = a.add(&b, p, RoundingMode::ToEven);
3810        let m = a.mul(&b, p, RoundingMode::ToEven);
3811        assert!(!s.is_nan(), "large-prec add hung or failed");
3812        assert!(!m.is_nan(), "large-prec mul hung or failed");
3813        assert_eq!(s.cmp(&ExactNum::from_word(8, p)), Some(0));
3814    }
3815
3816    #[test]
3817    fn test_two_sum_fused_polyval() {
3818        let p = 128;
3819        let rm = RoundingMode::ToEven;
3820        let one = ExactNum::from_u8(1, p);
3821        let two = ExactNum::from_u8(2, p);
3822        let three = ExactNum::from_u8(3, p);
3823
3824        let (hi, lo) = one.two_sum(&two, p, rm);
3825        let rec = hi.add(&lo, p, rm);
3826        assert_eq!(rec.cmp(&ExactNum::from_u8(3, p)), Some(0));
3827
3828        let (ph, pl) = two.two_product(&three, p, rm);
3829        let pr = ph.add(&pl, p, rm);
3830        assert_eq!(pr.cmp(&ExactNum::from_u8(6, p)), Some(0));
3831
3832        let sum = ExactNum::fused_sum(&[one.clone(), two.clone(), three.clone()], p, rm);
3833        assert_eq!(sum.cmp(&ExactNum::from_u8(6, p)), Some(0));
3834
3835        let dot = ExactNum::fused_dot(
3836            &[one.clone(), two.clone()],
3837            &[three.clone(), one.clone()],
3838            p,
3839            rm,
3840        );
3841        assert_eq!(dot.cmp(&ExactNum::from_u8(5, p)), Some(0));
3842
3843        // 1 + 2x + 3x² at x = 2 → 17
3844        let pv = ExactNum::polyval(&[one, two, three], &ExactNum::from_u8(2, p), p, rm);
3845        assert_eq!(pv.cmp(&ExactNum::from_u8(17, p)), Some(0));
3846    }
3847
3848    #[test]
3849    fn test_jacobi_sn_public() {
3850        let p = 256;
3851        let rm = RoundingMode::ToEven;
3852        let mut cc = Consts::new().unwrap();
3853        let one = ExactNum::from_u8(1, p);
3854        let zero = ExactNum::from_u8(0, p);
3855        let half = one.div(&ExactNum::from_u8(2, p), p, rm);
3856        let sn0 = zero.jacobi_sn(&half, p, rm, &mut cc);
3857        assert!(sn0.is_zero(), "sn(0)");
3858        let cn0 = zero.jacobi_cn(&half, p, rm, &mut cc);
3859        assert_eq!(cn0.cmp(&one), Some(0), "cn(0)");
3860        let sn_m0 = one.jacobi_sn(&zero, p, rm, &mut cc);
3861        let sin1 = one.sin(p, rm, &mut cc);
3862        let d = sn_m0.sub(&sin1, p, rm).abs();
3863        assert!(
3864            d.is_zero() || d.exponent().unwrap() < -80,
3865            "sn(1|0)=sin 1"
3866        );
3867        assert!(one
3868            .jacobi_sn(&ExactNum::from_i8(2, p), p, rm, &mut cc)
3869            .is_nan());
3870    }
3871}
3872
3873#[cfg(feature = "random")]
3874#[cfg(test)]
3875mod rand_tests {
3876
3877    use super::*;
3878    use crate::common::util::TEST_EXP_BOUND;
3879
3880    #[test]
3881    fn test_rand() {
3882        for _ in 0..100 {
3883            let p = crate::common::test_rng::random::<usize>() % 192 + DEFAULT_P;
3884            let exp_from = crate::common::test_rng::random::<Exponent>().abs() % TEST_EXP_BOUND;
3885            let span = (TEST_EXP_BOUND - exp_from).max(1);
3886            let exp_shift = crate::common::test_rng::random::<Exponent>().abs() % span;
3887            let exp_to = exp_from + exp_shift;
3888
3889            let n = ExactNum::random_normal(p, exp_from, exp_to);
3890
3891            assert!(!n.is_subnormal());
3892            assert!(n.exponent().unwrap() >= exp_from && n.exponent().unwrap() <= exp_to);
3893            assert!(n.precision().unwrap() >= p);
3894        }
3895    }
3896}