Skip to main content

astro_float_num/
ext.rs

1//! BigFloat including finite numbers, NaN, and `Inf`.
2
3use crate::defs::SignedWord;
4use crate::defs::DEFAULT_P;
5use crate::num::BigFloatNumber;
6use crate::Consts;
7use crate::Error;
8use crate::Exponent;
9use crate::Radix;
10use crate::RoundingMode;
11use crate::Sign;
12use crate::Word;
13use core::num::FpCategory;
14use lazy_static::lazy_static;
15
16#[cfg(feature = "std")]
17use core::fmt::Write;
18
19#[cfg(not(feature = "std"))]
20use alloc::{string::String, vec::Vec};
21
22/// Not a number.
23pub const NAN: BigFloat = BigFloat {
24    inner: Flavor::NaN(None),
25};
26
27/// Positive infinity.
28pub const INF_POS: BigFloat = BigFloat {
29    inner: Flavor::Inf(Sign::Pos),
30};
31
32/// Negative infinity.
33pub const INF_NEG: BigFloat = BigFloat {
34    inner: Flavor::Inf(Sign::Neg),
35};
36
37lazy_static! {
38
39    /// 1
40    pub static ref ONE: BigFloat = BigFloat { inner: Flavor::Value(BigFloatNumber::from_word(1, DEFAULT_P).expect("Constant ONE initialized")) };
41
42    /// 2
43    pub static ref TWO: BigFloat = BigFloat { inner: Flavor::Value(BigFloatNumber::from_word(2, DEFAULT_P).expect("Constant TWO initialized")) };
44}
45
46/// A floating point number of arbitrary precision.
47#[derive(Debug)]
48pub struct BigFloat {
49    inner: Flavor,
50}
51
52#[derive(Debug)]
53enum Flavor {
54    Value(BigFloatNumber),
55    NaN(Option<Error>),
56    Inf(Sign), // signed Inf
57}
58
59impl BigFloat {
60    /// Returns a new number with value of 0 and precision of `p` bits. Precision is rounded upwards to the word size.
61    /// The function returns NaN if the precision `p` is incorrect.
62    pub fn new(p: usize) -> Self {
63        Self::result_to_ext(BigFloatNumber::new(p), false, true)
64    }
65
66    /// Constructs a number with precision `p` from f64 value.
67    /// Precision is rounded upwards to the word size.
68    /// The function returns NaN if the precision `p` is incorrect.
69    pub fn from_f64(f: f64, p: usize) -> Self {
70        Self::result_to_ext(BigFloatNumber::from_f64(p, f), false, true)
71    }
72
73    /// Constructs not-a-number with an associated error `err`.
74    pub fn nan(err: Option<Error>) -> Self {
75        BigFloat {
76            inner: Flavor::NaN(err),
77        }
78    }
79
80    /// Constructs a number with precision `p` from f32 value.
81    /// Precision is rounded upwards to the word size.
82    /// The function returns NaN if the precision `p` is incorrect.
83    pub fn from_f32(f: f32, p: usize) -> Self {
84        Self::result_to_ext(BigFloatNumber::from_f64(p, f as f64), false, true)
85    }
86
87    /// Returns true if `self` is positive infinity.
88    pub fn is_inf_pos(&self) -> bool {
89        matches!(self.inner, Flavor::Inf(Sign::Pos))
90    }
91
92    /// Returns true if `self` is negative infinity.
93    pub fn is_inf_neg(&self) -> bool {
94        matches!(self.inner, Flavor::Inf(Sign::Neg))
95    }
96
97    /// Returns true if `self` is infinite.
98    pub fn is_inf(&self) -> bool {
99        matches!(self.inner, Flavor::Inf(_))
100    }
101
102    /// Return true if `self` is not a number.
103    pub fn is_nan(&self) -> bool {
104        matches!(self.inner, Flavor::NaN(_))
105    }
106
107    /// Return true if `self` is an integer number.
108    pub fn is_int(&self) -> bool {
109        match &self.inner {
110            Flavor::Value(v) => v.is_int(),
111            Flavor::NaN(_) => false,
112            Flavor::Inf(_) => false,
113        }
114    }
115
116    /// Returns the associated with NaN error, if any.
117    pub fn err(&self) -> Option<Error> {
118        match &self.inner {
119            Flavor::NaN(Some(e)) => Some(*e),
120            _ => None,
121        }
122    }
123
124    /// Adds `d2` to `self` and returns the result of the operation with precision `p` rounded according to `rm`.
125    /// Precision is rounded upwards to the word size.
126    /// The function returns NaN if the precision `p` is incorrect.
127    pub fn add(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
128        self.add_op(d2, p, rm, false)
129    }
130
131    /// Adds `d2` to `self` and returns the result of the operation.
132    /// The resulting precision is equal to the full precision of the result.
133    /// This operation can be used to emulate integer addition.
134    pub fn add_full_prec(&self, d2: &Self) -> Self {
135        self.add_op(d2, 0, RoundingMode::None, true)
136    }
137
138    fn add_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
139        match &self.inner {
140            Flavor::Value(v1) => match &d2.inner {
141                Flavor::Value(v2) => Self::result_to_ext(
142                    if full_prec { v1.add_full_prec(v2) } else { v1.add(v2, p, rm) },
143                    v1.is_zero(),
144                    v1.sign() == v2.sign(),
145                ),
146                Flavor::Inf(s2) => BigFloat {
147                    inner: Flavor::Inf(*s2),
148                },
149                Flavor::NaN(err) => Self::nan(*err),
150            },
151            Flavor::Inf(s1) => match &d2.inner {
152                Flavor::Value(_) => BigFloat {
153                    inner: Flavor::Inf(*s1),
154                },
155                Flavor::Inf(s2) => {
156                    if *s1 != *s2 {
157                        NAN
158                    } else {
159                        BigFloat {
160                            inner: Flavor::Inf(*s2),
161                        }
162                    }
163                }
164                Flavor::NaN(err) => Self::nan(*err),
165            },
166            Flavor::NaN(err) => Self::nan(*err),
167        }
168    }
169
170    /// Subtracts `d2` from `self` and returns the result of the operation with precision `p` rounded according to `rm`.
171    /// Precision is rounded upwards to the word size.
172    /// The function returns NaN if the precision `p` is incorrect.
173    pub fn sub(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
174        self.sub_op(d2, p, rm, false)
175    }
176
177    /// Subtracts `d2` from `self` and returns the result of the operation.
178    /// The resulting precision is equal to the full precision of the result.
179    /// This operation can be used to emulate integer subtraction.
180    pub fn sub_full_prec(&self, d2: &Self) -> Self {
181        self.sub_op(d2, 0, RoundingMode::None, true)
182    }
183
184    fn sub_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
185        match &self.inner {
186            Flavor::Value(v1) => match &d2.inner {
187                Flavor::Value(v2) => Self::result_to_ext(
188                    if full_prec { v1.sub_full_prec(v2) } else { v1.sub(v2, p, rm) },
189                    v1.is_zero(),
190                    v1.sign() == v2.sign(),
191                ),
192                Flavor::Inf(s2) => {
193                    if s2.is_positive() {
194                        INF_NEG
195                    } else {
196                        INF_POS
197                    }
198                }
199                Flavor::NaN(err) => Self::nan(*err),
200            },
201            Flavor::Inf(s1) => match &d2.inner {
202                Flavor::Value(_) => BigFloat {
203                    inner: Flavor::Inf(*s1),
204                },
205                Flavor::Inf(s2) => {
206                    if *s1 == *s2 {
207                        NAN
208                    } else {
209                        BigFloat {
210                            inner: Flavor::Inf(*s1),
211                        }
212                    }
213                }
214                Flavor::NaN(err) => Self::nan(*err),
215            },
216            Flavor::NaN(err) => Self::nan(*err),
217        }
218    }
219
220    /// Multiplies `d2` by `self` and returns the result of the operation with precision `p` rounded according to `rm`.
221    /// Precision is rounded upwards to the word size.
222    /// The function returns NaN if the precision `p` is incorrect.
223    pub fn mul(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
224        self.mul_op(d2, p, rm, false)
225    }
226
227    /// Multiplies `d2` by `self` and returns the result of the operation.
228    /// The resulting precision is equal to the full precision of the result.
229    /// This operation can be used to emulate integer multiplication.
230    pub fn mul_full_prec(&self, d2: &Self) -> Self {
231        self.mul_op(d2, 0, RoundingMode::None, true)
232    }
233
234    fn mul_op(&self, d2: &Self, p: usize, rm: RoundingMode, full_prec: bool) -> Self {
235        match &self.inner {
236            Flavor::Value(v1) => {
237                match &d2.inner {
238                    Flavor::Value(v2) => Self::result_to_ext(
239                        if full_prec { v1.mul_full_prec(v2) } else { v1.mul(v2, p, rm) },
240                        v1.is_zero(),
241                        v1.sign() == v2.sign(),
242                    ),
243                    Flavor::Inf(s2) => {
244                        if v1.is_zero() {
245                            // 0*inf
246                            NAN
247                        } else {
248                            let s = if v1.sign() == *s2 { Sign::Pos } else { Sign::Neg };
249                            BigFloat {
250                                inner: Flavor::Inf(s),
251                            }
252                        }
253                    }
254                    Flavor::NaN(err) => Self::nan(*err),
255                }
256            }
257            Flavor::Inf(s1) => {
258                match &d2.inner {
259                    Flavor::Value(v2) => {
260                        if v2.is_zero() {
261                            // inf*0
262                            NAN
263                        } else {
264                            let s = if v2.sign() == *s1 { Sign::Pos } else { Sign::Neg };
265                            BigFloat {
266                                inner: Flavor::Inf(s),
267                            }
268                        }
269                    }
270                    Flavor::Inf(s2) => {
271                        let s = if s1 == s2 { Sign::Pos } else { Sign::Neg };
272                        BigFloat {
273                            inner: Flavor::Inf(s),
274                        }
275                    }
276                    Flavor::NaN(err) => Self::nan(*err),
277                }
278            }
279            Flavor::NaN(err) => Self::nan(*err),
280        }
281    }
282
283    /// Divides `self` by `d2` and returns the result of the operation with precision `p` rounded according to `rm`.
284    /// Precision is rounded upwards to the word size.
285    /// The function returns NaN if the precision `p` is incorrect.
286    pub fn div(&self, d2: &Self, p: usize, rm: RoundingMode) -> Self {
287        match &self.inner {
288            Flavor::Value(v1) => match &d2.inner {
289                Flavor::Value(v2) => {
290                    Self::result_to_ext(v1.div(v2, p, rm), v1.is_zero(), v1.sign() == v2.sign())
291                }
292                Flavor::Inf(_) => Self::new(v1.mantissa_max_bit_len()),
293                Flavor::NaN(err) => Self::nan(*err),
294            },
295            Flavor::Inf(s1) => match &d2.inner {
296                Flavor::Value(v) => {
297                    if *s1 == v.sign() {
298                        INF_POS
299                    } else {
300                        INF_NEG
301                    }
302                }
303                Flavor::Inf(_) => NAN,
304                Flavor::NaN(err) => Self::nan(*err),
305            },
306            Flavor::NaN(err) => Self::nan(*err),
307        }
308    }
309
310    /// Returns the remainder of division of `|self|` by `|d2|`. The sign of the result is set to the sign of `self`.
311    pub fn rem(&self, d2: &Self) -> Self {
312        match &self.inner {
313            Flavor::Value(v1) => match &d2.inner {
314                Flavor::Value(v2) => {
315                    Self::result_to_ext(v1.rem(v2), v1.is_zero(), v1.sign() == v2.sign())
316                }
317                Flavor::Inf(_) => self.clone(),
318                Flavor::NaN(err) => Self::nan(*err),
319            },
320            Flavor::Inf(_) => NAN,
321            Flavor::NaN(err) => Self::nan(*err),
322        }
323    }
324
325    /// Compares `self` to `d2`.
326    /// Returns positive if `self` > `d2`, negative if `self` < `d2`, zero if `self` == `d2`, None if `self` or `d2` is NaN.
327    #[allow(clippy::should_implement_trait)]
328    pub fn cmp(&self, d2: &BigFloat) -> Option<SignedWord> {
329        match &self.inner {
330            Flavor::Value(v1) => match &d2.inner {
331                Flavor::Value(v2) => Some(v1.cmp(v2)),
332                Flavor::Inf(s2) => {
333                    if *s2 == Sign::Pos {
334                        Some(-1)
335                    } else {
336                        Some(1)
337                    }
338                }
339                Flavor::NaN(_) => None,
340            },
341            Flavor::Inf(s1) => match &d2.inner {
342                Flavor::Value(_) => Some(*s1 as SignedWord),
343                Flavor::Inf(s2) => Some(*s1 as SignedWord - *s2 as SignedWord),
344                Flavor::NaN(_) => None,
345            },
346            Flavor::NaN(_) => None,
347        }
348    }
349
350    /// Compares the absolute value of `self` to the absolute value of `d2`.
351    /// 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.
352    pub fn abs_cmp(&self, d2: &Self) -> Option<SignedWord> {
353        match &self.inner {
354            Flavor::Value(v1) => match &d2.inner {
355                Flavor::Value(v2) => Some(v1.cmp(v2)),
356                Flavor::Inf(_) => Some(-1),
357                Flavor::NaN(_) => None,
358            },
359            Flavor::Inf(_) => match &d2.inner {
360                Flavor::Value(_) => Some(1),
361                Flavor::Inf(_) => Some(0),
362                Flavor::NaN(_) => None,
363            },
364            Flavor::NaN(_) => None,
365        }
366    }
367
368    /// Reverses the sign of `self`.
369    pub fn inv_sign(&mut self) {
370        match &mut self.inner {
371            Flavor::Value(v1) => v1.inv_sign(),
372            Flavor::Inf(s) => self.inner = Flavor::Inf(s.invert()),
373            Flavor::NaN(_) => {}
374        }
375    }
376
377    /// Compute the power of `self` to the `n` with precision `p`. The result is rounded using the rounding mode `rm`.
378    /// This function requires constants cache `cc` for computing the result.
379    /// Precision is rounded upwards to the word size.
380    /// The function returns NaN if the precision `p` is incorrect.
381    pub fn pow(&self, n: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
382        match &self.inner {
383            Flavor::Value(v1) => {
384                match &n.inner {
385                    Flavor::Value(v2) => Self::result_to_ext(
386                        v1.pow(v2, p, rm, cc),
387                        v1.is_zero(),
388                        v1.sign() == v2.sign(),
389                    ),
390                    Flavor::Inf(s2) => {
391                        // v1^inf
392                        let val = v1.cmp(&crate::common::consts::ONE);
393                        if val > 0 {
394                            BigFloat {
395                                inner: Flavor::Inf(*s2),
396                            }
397                        } else if val < 0 {
398                            Self::new(p)
399                        } else {
400                            Self::from_u8(1, p)
401                        }
402                    }
403                    Flavor::NaN(err) => Self::nan(*err),
404                }
405            }
406            Flavor::Inf(s1) => {
407                match &n.inner {
408                    Flavor::Value(v2) => {
409                        // inf ^ v2
410                        if v2.is_zero() {
411                            Self::from_u8(1, p)
412                        } else if v2.is_positive() {
413                            if s1.is_negative() && v2.is_odd_int() {
414                                // v2 is odd and has no fractional part.
415                                INF_NEG
416                            } else {
417                                INF_POS
418                            }
419                        } else {
420                            Self::new(p)
421                        }
422                    }
423                    Flavor::Inf(s2) => {
424                        // inf^inf
425                        if s2.is_positive() {
426                            INF_POS
427                        } else {
428                            Self::new(p)
429                        }
430                    }
431                    Flavor::NaN(err) => Self::nan(*err),
432                }
433            }
434            Flavor::NaN(err) => Self::nan(*err),
435        }
436    }
437
438    /// Compute the power of `self` to the integer `n` with precision `p`. The result is rounded using the rounding mode `rm`.
439    /// Precision is rounded upwards to the word size.
440    /// The function returns NaN if the precision `p` is incorrect.
441    pub fn powi(&self, n: usize, p: usize, rm: RoundingMode) -> Self {
442        match &self.inner {
443            Flavor::Value(v1) => Self::result_to_ext(v1.powi(n, p, rm), false, true),
444            Flavor::Inf(s1) => {
445                // inf ^ v2
446                if n == 0 {
447                    Self::from_u8(1, p)
448                } else if s1.is_negative() && (n & 1 == 1) {
449                    INF_NEG
450                } else {
451                    INF_POS
452                }
453            }
454            Flavor::NaN(err) => Self::nan(*err),
455        }
456    }
457
458    /// Computes the logarithm base `n` of a number with precision `p`. The result is rounded using the rounding mode `rm`.
459    /// This function requires constants cache `cc` for computing the result.
460    /// Precision is rounded upwards to the word size.
461    /// The function returns NaN if the precision `p` is incorrect.
462    pub fn log(&self, n: &Self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
463        match &self.inner {
464            Flavor::Value(v1) => {
465                match &n.inner {
466                    Flavor::Value(v2) => {
467                        if v2.is_zero() {
468                            return INF_NEG;
469                        }
470                        Self::result_to_ext(v1.log(v2, p, rm, cc), false, true)
471                    }
472                    Flavor::Inf(s2) => {
473                        // v1.log(inf)
474                        if s2.is_positive() {
475                            Self::new(p)
476                        } else {
477                            NAN
478                        }
479                    }
480                    Flavor::NaN(err) => Self::nan(*err),
481                }
482            }
483            Flavor::Inf(s1) => {
484                if *s1 == Sign::Neg {
485                    // -inf.log(any)
486                    NAN
487                } else {
488                    match &n.inner {
489                        Flavor::Value(v2) => {
490                            // +inf.log(v2)
491                            if v2.exponent() <= 0 {
492                                INF_NEG
493                            } else {
494                                INF_POS
495                            }
496                        }
497                        Flavor::Inf(_) => NAN, // +inf.log(inf)
498                        Flavor::NaN(err) => Self::nan(*err),
499                    }
500                }
501            }
502            Flavor::NaN(err) => Self::nan(*err),
503        }
504    }
505
506    /// Returns true if `self` is positive.
507    /// The function returns false if `self` is NaN.
508    pub fn is_positive(&self) -> bool {
509        match &self.inner {
510            Flavor::Value(v) => v.is_positive(),
511            Flavor::Inf(s) => *s == Sign::Pos,
512            Flavor::NaN(_) => false,
513        }
514    }
515
516    /// Returns true if `self` is negative.
517    /// The function returns false if `self` is NaN.
518    pub fn is_negative(&self) -> bool {
519        match &self.inner {
520            Flavor::Value(v) => v.is_negative(),
521            Flavor::Inf(s) => *s == Sign::Neg,
522            Flavor::NaN(_) => false,
523        }
524    }
525
526    /// Returns true if `self` is subnormal. A number is subnormal if the most significant bit of the mantissa is not equal to 1.
527    pub fn is_subnormal(&self) -> bool {
528        if let Flavor::Value(v) = &self.inner {
529            return v.is_subnormal();
530        }
531        false
532    }
533
534    /// Returns true if `self` is zero.
535    pub fn is_zero(&self) -> bool {
536        match &self.inner {
537            Flavor::Value(v) => v.is_zero(),
538            Flavor::Inf(_) => false,
539            Flavor::NaN(_) => false,
540        }
541    }
542
543    /// Restricts the value of `self` to an interval determined by the values of `min` and `max`.
544    /// The function returns `max` if `self` is greater than `max`, `min` if `self` is less than `min`, and `self` otherwise.
545    /// If either argument is NaN or `min` is greater than `max`, the function returns NaN.
546    pub fn clamp(&self, min: &Self, max: &Self) -> Self {
547        if self.is_nan() || min.is_nan() || max.is_nan() || max.cmp(min).unwrap() < 0 {
548            // call to unwrap() is unreacheable
549            NAN
550        } else if self.cmp(min).unwrap() < 0 {
551            // call to unwrap() is unreacheable
552            min.clone()
553        } else if self.cmp(max).unwrap() > 0 {
554            // call to unwrap() is unreacheable
555            max.clone()
556        } else {
557            self.clone()
558        }
559    }
560
561    /// Returns the value of `d1` if `d1` is greater than `self`, or the value of `self` otherwise.
562    /// If either argument is NaN, the function returns NaN.
563    pub fn max(&self, d1: &Self) -> Self {
564        if self.is_nan() || d1.is_nan() {
565            NAN
566        } else if self.cmp(d1).unwrap() < 0 {
567            // call to unwrap() is unreacheable
568            d1.clone()
569        } else {
570            self.clone()
571        }
572    }
573
574    /// Returns value of `d1` if `d1` is less than `self`, or the value of `self` otherwise.
575    /// If either argument is NaN, the function returns NaN.
576    pub fn min(&self, d1: &Self) -> Self {
577        if self.is_nan() || d1.is_nan() {
578            NAN
579        } else if self.cmp(d1).unwrap() > 0 {
580            // call to unwrap() is unreacheable
581            d1.clone()
582        } else {
583            self.clone()
584        }
585    }
586
587    /// Returns a BigFloat with the value -1 if `self` is negative, 1 if `self` is positive, zero otherwise.
588    /// The function returns NaN If `self` is NaN.
589    pub fn signum(&self) -> Self {
590        if self.is_nan() {
591            NAN
592        } else if self.is_negative() {
593            let mut ret = Self::from_u8(1, DEFAULT_P);
594            ret.inv_sign();
595            ret
596        } else {
597            Self::from_u8(1, DEFAULT_P)
598        }
599    }
600
601    /// Parses a number from the string `s`.
602    /// The function expects `s` to be a number in scientific format in radix `rdx`, or +-Inf, or NaN.
603    /// if `p` equals to usize::MAX then the precision of the resulting number is determined automatically from the input.
604    ///
605    /// ## Examples
606    ///
607    /// ```
608    /// # use astro_float_num::BigFloat;
609    /// # use astro_float_num::Radix;
610    /// # use astro_float_num::RoundingMode;
611    /// # use astro_float_num::Consts;
612    /// let mut cc = Consts::new().expect("Constants cache initialized.");
613    ///
614    /// let n = BigFloat::parse("0.0", Radix::Bin, 64, RoundingMode::ToEven, &mut cc);
615    /// assert!(n.is_zero());
616    ///
617    /// let n = BigFloat::parse("1.124e-24", Radix::Dec, 128, RoundingMode::ToEven, &mut cc);
618    /// assert!(n.sub(&BigFloat::from_f64(1.124e-24, 128), 128, RoundingMode::ToEven).exponent() <= Some(-52 - 24));
619    ///
620    /// let n = BigFloat::parse("-Inf", Radix::Hex, 1, RoundingMode::None, &mut cc);
621    /// assert!(n.is_inf_neg());
622    ///
623    /// let n = BigFloat::parse("NaN", Radix::Oct, 2, RoundingMode::None, &mut cc);
624    /// assert!(n.is_nan());
625    /// ```
626    pub fn parse(s: &str, rdx: Radix, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
627        match crate::parser::parse(s, rdx) {
628            Ok(ps) => {
629                if ps.is_inf() {
630                    if ps.sign() == Sign::Pos {
631                        INF_POS
632                    } else {
633                        INF_NEG
634                    }
635                } else if ps.is_nan() {
636                    NAN
637                } else {
638                    let (m, s, e) = ps.raw_parts();
639                    Self::result_to_ext(
640                        BigFloatNumber::convert_from_radix(s, m, e, rdx, p, rm, cc),
641                        false,
642                        true,
643                    )
644                }
645            }
646            Err(e) => Self::nan(Some(e)),
647        }
648    }
649
650    #[cfg(feature = "std")]
651    pub(crate) fn write_str<T: Write>(
652        &self,
653        w: &mut T,
654        rdx: Radix,
655        rm: RoundingMode,
656        cc: &mut Consts,
657    ) -> Result<(), core::fmt::Error> {
658        match &self.inner {
659            Flavor::Value(v) => match v.format(rdx, rm, cc) {
660                Ok(s) => w.write_str(&s),
661                Err(e) => match e {
662                    Error::ExponentOverflow(s) => {
663                        if s.is_positive() {
664                            w.write_str("Inf")
665                        } else {
666                            w.write_str("-Inf")
667                        }
668                    }
669                    _ => w.write_str("Err"),
670                },
671            },
672            Flavor::Inf(sign) => {
673                let s = if sign.is_negative() { "-Inf" } else { "Inf" };
674                w.write_str(s)
675            }
676            crate::ext::Flavor::NaN(_) => w.write_str("NaN"),
677        }
678    }
679
680    /// Formats the number using radix `rdx` and rounding mode `rm`.
681    /// Note, since hexadecimal digits include the character "e", the exponent part is separated
682    /// from the mantissa by "_".
683    /// For example, a number with mantissa `123abcdef` and exponent `123` would be formatted as `123abcdef_e+123`.
684    ///
685    /// ## Errors
686    ///
687    ///  - MemoryAllocation: failed to allocate memory for mantissa.
688    ///  - ExponentOverflow: the resulting exponent becomes greater than the maximum allowed value for the exponent.
689    pub fn format(&self, rdx: Radix, rm: RoundingMode, cc: &mut Consts) -> Result<String, Error> {
690        let s = match &self.inner {
691            Flavor::Value(v) => match v.format(rdx, rm, cc) {
692                Ok(s) => return Ok(s),
693                Err(e) => match e {
694                    Error::ExponentOverflow(s) => {
695                        if s.is_positive() {
696                            "Inf"
697                        } else {
698                            "-Inf"
699                        }
700                    }
701                    _ => "Err",
702                },
703            },
704            Flavor::Inf(sign) => {
705                if sign.is_negative() {
706                    "-Inf"
707                } else {
708                    "Inf"
709                }
710            }
711            crate::ext::Flavor::NaN(_) => "NaN",
712        };
713
714        let mut ret = String::new();
715        ret.try_reserve_exact(s.len())?;
716        ret.push_str(s);
717
718        Ok(ret)
719    }
720
721    /// Returns a random normalized (not subnormal) BigFloat number with exponent in the range
722    /// from `exp_from` to `exp_to` inclusive. The sign can be positive and negative. Zero is excluded.
723    /// Precision is rounded upwards to the word size.
724    /// Function does not follow any specific distribution law.
725    /// The intended use of this function is for testing.
726    /// 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.
727    #[cfg(feature = "random")]
728    pub fn random_normal(p: usize, exp_from: Exponent, exp_to: Exponent) -> Self {
729        Self::result_to_ext(
730            BigFloatNumber::random_normal(p, exp_from, exp_to),
731            false,
732            true,
733        )
734    }
735
736    /// Returns category of `self`.
737    pub fn classify(&self) -> FpCategory {
738        match &self.inner {
739            Flavor::Value(v) => {
740                if v.is_subnormal() {
741                    FpCategory::Subnormal
742                } else if v.is_zero() {
743                    FpCategory::Zero
744                } else {
745                    FpCategory::Normal
746                }
747            }
748            Flavor::Inf(_) => FpCategory::Infinite,
749            Flavor::NaN(_) => FpCategory::Nan,
750        }
751    }
752
753    /// Computes the arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
754    /// This function requires constants cache `cc` for computing the result.
755    /// Precision is rounded upwards to the word size.
756    /// The function returns NaN if the precision `p` is incorrect.
757    pub fn atan(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
758        match &self.inner {
759            Flavor::Value(v) => Self::result_to_ext(v.atan(p, rm, cc), v.is_zero(), true),
760            Flavor::Inf(s) => Self::result_to_ext(Self::half_pi(*s, p, rm, cc), false, true),
761            Flavor::NaN(err) => Self::nan(*err),
762        }
763    }
764
765    /// Computes the hyperbolic tangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
766    /// This function requires constants cache `cc` for computing the result.
767    /// Precision is rounded upwards to the word size.
768    /// The function returns NaN if the precision `p` is incorrect.
769    pub fn tanh(&self, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
770        match &self.inner {
771            Flavor::Value(v) => Self::result_to_ext(v.tanh(p, rm, cc), v.is_zero(), true),
772            Flavor::Inf(s) => Self::from_i8(s.to_int(), p),
773            Flavor::NaN(err) => Self::nan(*err),
774        }
775    }
776
777    fn half_pi(
778        s: Sign,
779        p: usize,
780        rm: RoundingMode,
781        cc: &mut Consts,
782    ) -> Result<BigFloatNumber, Error> {
783        let mut half_pi = cc.pi_num(p, rm)?;
784
785        half_pi.set_exponent(1);
786        half_pi.set_sign(s);
787
788        Ok(half_pi)
789    }
790
791    fn result_to_ext(
792        res: Result<BigFloatNumber, Error>,
793        is_dividend_zero: bool,
794        is_same_sign: bool,
795    ) -> BigFloat {
796        match res {
797            Err(e) => match e {
798                Error::ExponentOverflow(s) => {
799                    if s.is_positive() {
800                        INF_POS
801                    } else {
802                        INF_NEG
803                    }
804                }
805                Error::DivisionByZero => {
806                    if is_dividend_zero {
807                        NAN
808                    } else if is_same_sign {
809                        INF_POS
810                    } else {
811                        INF_NEG
812                    }
813                }
814                Error::MemoryAllocation => Self::nan(Some(Error::MemoryAllocation)),
815                Error::InvalidArgument => Self::nan(Some(Error::InvalidArgument)),
816            },
817            Ok(v) => BigFloat {
818                inner: Flavor::Value(v),
819            },
820        }
821    }
822
823    /// Returns the exponent of `self`, or None if `self` is Inf or NaN.
824    pub fn exponent(&self) -> Option<Exponent> {
825        match &self.inner {
826            Flavor::Value(v) => Some(v.exponent()),
827            _ => None,
828        }
829    }
830
831    /// Returns the number of significant bits used in the mantissa, or None if `self` is Inf or NaN.
832    /// Normal numbers use all bits of the mantissa.
833    /// Subnormal numbers use fewer bits than the mantissa can hold.
834    pub fn precision(&self) -> Option<usize> {
835        match &self.inner {
836            Flavor::Value(v) => Some(v.precision()),
837            _ => None,
838        }
839    }
840
841    /// Returns the maximum value for the specified precision `p`: all bits of the mantissa are set to 1,
842    /// the exponent has the maximum possible value, and the sign is positive.
843    /// Precision is rounded upwards to the word size.
844    /// The function returns NaN if the precision `p` is incorrect.
845    pub fn max_value(p: usize) -> Self {
846        Self::result_to_ext(BigFloatNumber::max_value(p), false, true)
847    }
848
849    /// 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.
850    /// The function returns NaN if the precision `p` is incorrect.
851    pub fn min_value(p: usize) -> Self {
852        Self::result_to_ext(BigFloatNumber::min_value(p), false, true)
853    }
854
855    /// Returns the minimum positive subnormal value for the specified precision `p`:
856    /// only the least significant bit of the mantissa is set to 1, the exponent has
857    /// the minimum possible value, and the sign is positive.
858    /// Precision is rounded upwards to the word size.
859    /// The function returns NaN if the precision `p` is incorrect.
860    pub fn min_positive(p: usize) -> Self {
861        Self::result_to_ext(BigFloatNumber::min_positive(p), false, true)
862    }
863
864    /// Returns the minimum positive normal value for the specified precision `p`:
865    /// only the most significant bit of the mantissa is set to 1, the exponent has
866    /// the minimum possible value, and the sign is positive.
867    /// Precision is rounded upwards to the word size.
868    /// The function returns NaN if the precision `p` is incorrect.
869    pub fn min_positive_normal(p: usize) -> Self {
870        Self::result_to_ext(BigFloatNumber::min_positive_normal(p), false, true)
871    }
872
873    /// Returns a new number with value `d` and the precision `p`. Precision is rounded upwards to the word size.
874    /// The function returns NaN if the precision `p` is incorrect.
875    pub fn from_word(d: Word, p: usize) -> Self {
876        Self::result_to_ext(BigFloatNumber::from_word(d, p), false, true)
877    }
878
879    /// Returns a copy of the number with the sign reversed.
880    pub fn neg(&self) -> Self {
881        let mut ret = self.clone();
882        ret.inv_sign();
883        ret
884    }
885
886    /// Decomposes `self` into raw parts.
887    /// The function returns a reference to a slice of words representing mantissa,
888    /// numbers of significant bits in the mantissa, sign, exponent,
889    /// and a bool value which specify whether the number is inexact.
890    pub fn as_raw_parts(&self) -> Option<(&[Word], usize, Sign, Exponent, bool)> {
891        if let Flavor::Value(v) = &self.inner {
892            Some(v.as_raw_parts())
893        } else {
894            None
895        }
896    }
897
898    /// Constructs a number from the raw parts:
899    ///
900    ///  - `m` is the mantisaa.
901    ///  - `n` is the number of significant bits in mantissa.
902    ///  - `s` is the sign.
903    ///  - `e` is the exponent.
904    ///  - `inexact` specify whether number is inexact.
905    ///
906    /// This function returns NaN in the following situations:
907    ///
908    /// - `n` is larger than the number of bits in `m`.
909    /// - `n` is smaller than the number of bits in `m`, but `m` does not represent corresponding subnormal number mantissa.
910    /// - `n` is smaller than the number of bits in `m`, but `e` is not the minimum possible exponent.
911    /// - `n` or the size of `m` is too large (larger than isize::MAX / 2 + EXPONENT_MIN).
912    /// - `e` is less than EXPONENT_MIN or greater than EXPONENT_MAX.
913    pub fn from_raw_parts(m: &[Word], n: usize, s: Sign, e: Exponent, inexact: bool) -> Self {
914        Self::result_to_ext(
915            BigFloatNumber::from_raw_parts(m, n, s, e, inexact),
916            false,
917            true,
918        )
919    }
920
921    /// Constructs a number from the slice of words:
922    ///
923    ///  - `m` is the mantissa.
924    ///  - `s` is the sign.
925    ///  - `e` is the exponent.
926    ///
927    /// The function returns NaN if `e` is less than EXPONENT_MIN or greater than EXPONENT_MAX.
928    pub fn from_words(m: &[Word], s: Sign, e: Exponent) -> Self {
929        Self::result_to_ext(BigFloatNumber::from_words(m, s, e), false, true)
930    }
931
932    /// Returns the sign of `self`, or None if `self` is NaN.
933    pub fn sign(&self) -> Option<Sign> {
934        match &self.inner {
935            Flavor::Value(v) => Some(v.sign()),
936            Flavor::Inf(s) => Some(*s),
937            Flavor::NaN(_) => None,
938        }
939    }
940
941    /// Sets the exponent of `self`.
942    /// Note that if `self` is subnormal, the exponent may not change, but the mantissa will shift instead.
943    /// `e` will be clamped to the range from EXPONENT_MIN to EXPONENT_MAX if it's outside of the range.
944    /// See example below.
945    ///
946    /// ## Examples
947    ///
948    /// ```
949    /// # use astro_float_num::BigFloat;
950    /// # use astro_float_num::EXPONENT_MIN;
951    /// // construct a subnormal value.
952    /// let mut n = BigFloat::min_positive(128);
953    ///
954    /// assert_eq!(n.exponent(), Some(EXPONENT_MIN));
955    /// assert_eq!(n.precision(), Some(1));
956    ///
957    /// // increase exponent.
958    /// let n_exp = n.exponent().expect("n is not NaN");
959    /// n.set_exponent(n_exp + 1);
960    ///
961    /// // the outcome for subnormal number.
962    /// assert_eq!(n.exponent(), Some(EXPONENT_MIN));
963    /// assert_eq!(n.precision(), Some(2));
964    /// ```
965    pub fn set_exponent(&mut self, e: Exponent) {
966        if let Flavor::Value(v) = &mut self.inner {
967            v.set_exponent(e)
968        }
969    }
970
971    /// Returns the maximum mantissa length of `self` in bits regardless of whether `self` is normal or subnormal.
972    pub fn mantissa_max_bit_len(&self) -> Option<usize> {
973        if let Flavor::Value(v) = &self.inner {
974            Some(v.mantissa_max_bit_len())
975        } else {
976            None
977        }
978    }
979
980    /// Sets the precision of `self` to `p`.
981    /// If the new precision is smaller than the existing one, the number is rounded using specified rounding mode `rm`.
982    ///
983    /// ## Errors
984    ///
985    ///  - MemoryAllocation: failed to allocate memory for mantissa.
986    ///  - InvalidArgument: the precision is incorrect.
987    pub fn set_precision(&mut self, p: usize, rm: RoundingMode) -> Result<(), Error> {
988        if let Flavor::Value(v) = &mut self.inner {
989            v.set_precision(p, rm)
990        } else {
991            Ok(())
992        }
993    }
994
995    /// Computes the reciprocal of a number with precision `p`.
996    /// The result is rounded using the rounding mode `rm`.
997    /// Precision is rounded upwards to the word size.
998    /// The function returns NaN if the precision `p` is incorrect.
999    pub fn reciprocal(&self, p: usize, rm: RoundingMode) -> Self {
1000        match &self.inner {
1001            Flavor::Value(v) => Self::result_to_ext(v.reciprocal(p, rm), false, v.is_positive()),
1002            Flavor::Inf(s) => {
1003                let mut ret = Self::new(p);
1004                ret.set_sign(*s);
1005                ret
1006            }
1007            Flavor::NaN(err) => Self::nan(*err),
1008        }
1009    }
1010
1011    /// Sets the sign of `self`.
1012    pub fn set_sign(&mut self, s: Sign) {
1013        match &mut self.inner {
1014            Flavor::Value(v) => v.set_sign(s),
1015            Flavor::Inf(_) => self.inner = Flavor::Inf(s),
1016            Flavor::NaN(_) => {}
1017        };
1018    }
1019
1020    /// Returns the raw mantissa words of a number.
1021    pub fn mantissa_digits(&self) -> Option<&[Word]> {
1022        if let Flavor::Value(v) = &self.inner {
1023            Some(v.mantissa().digits())
1024        } else {
1025            None
1026        }
1027    }
1028
1029    /// Converts an array of digits in radix `rdx` to BigFloat with precision `p`.
1030    /// `digits` represents mantissa and is interpreted as a number smaller than 1 and greater or equal to 1/`rdx`.
1031    /// The first element in `digits` is the most significant digit.
1032    /// `e` is the exponent part of the number, such that the number can be represented as `digits` * `rdx` ^ `e`.
1033    /// Precision is rounded upwards to the word size.
1034    /// if `p` equals usize::MAX then the precision of the resulting number is determined automatically from the input.
1035    ///
1036    /// ## Examples
1037    ///
1038    /// Code below converts `-0.1234567₈ × 10₈^3₈` given in radix 8 to BigFloat.
1039    ///
1040    /// ``` rust
1041    /// # use astro_float_num::{BigFloat, Sign, RoundingMode, Radix, Consts};
1042    /// let mut cc = Consts::new().expect("Constants cache initialized.");
1043    ///
1044    /// let g = BigFloat::convert_from_radix(
1045    ///     Sign::Neg,
1046    ///     &[1, 2, 3, 4, 5, 6, 7, 0],
1047    ///     3,
1048    ///     Radix::Oct,
1049    ///     64,
1050    ///     RoundingMode::None,
1051    ///     &mut cc);
1052    ///
1053    /// let n = BigFloat::from_f64(-83.591552734375, 64);
1054    ///
1055    /// assert_eq!(n.cmp(&g), Some(0));
1056    /// ```
1057    ///
1058    /// ## Errors
1059    ///
1060    /// On error, the function returns NaN with the following associated error:
1061    ///
1062    ///  - MemoryAllocation: failed to allocate memory for mantissa.
1063    ///  - ExponentOverflow: the resulting exponent becomes greater than the maximum allowed value for the exponent.
1064    ///  - InvalidArgument: the precision is incorrect, or `digits` contains unacceptable digits for given radix,
1065    /// or when `e` is less than EXPONENT_MIN or greater than EXPONENT_MAX.
1066    pub fn convert_from_radix(
1067        sign: Sign,
1068        digits: &[u8],
1069        e: Exponent,
1070        rdx: Radix,
1071        p: usize,
1072        rm: RoundingMode,
1073        cc: &mut Consts,
1074    ) -> Self {
1075        Self::result_to_ext(
1076            BigFloatNumber::convert_from_radix(sign, digits, e, rdx, p, rm, cc),
1077            false,
1078            true,
1079        )
1080    }
1081
1082    /// Converts `self` to radix `rdx` using rounding mode `rm`.
1083    /// The function returns sign, mantissa digits in radix `rdx`, and exponent such that the converted number
1084    /// can be represented as `mantissa digits` * `rdx` ^ `exponent`.
1085    /// The first element in the mantissa is the most significant digit.
1086    ///
1087    /// ## Examples
1088    ///
1089    /// ``` rust
1090    /// # use astro_float_num::{BigFloat, Sign, RoundingMode, Radix, Consts};
1091    /// let n = BigFloat::from_f64(0.00012345678f64, 64);
1092    ///
1093    /// let mut cc = Consts::new().expect("Constants cache initialized.");
1094    ///
1095    /// let (s, m, e) = n.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc).expect("Conversion failed");
1096    ///
1097    /// assert_eq!(s, Sign::Pos);
1098    /// assert_eq!(m, [1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 4]);
1099    /// assert_eq!(e, -3);
1100    /// ```
1101    ///
1102    /// ## Errors
1103    ///
1104    ///  - MemoryAllocation: failed to allocate memory for mantissa.
1105    ///  - ExponentOverflow: the resulting exponent becomes greater than the maximum allowed value for the exponent.
1106    ///  - InvalidArgument: `self` is Inf or NaN.
1107    pub fn convert_to_radix(
1108        &self,
1109        rdx: Radix,
1110        rm: RoundingMode,
1111        cc: &mut Consts,
1112    ) -> Result<(Sign, Vec<u8>, Exponent), Error> {
1113        match &self.inner {
1114            Flavor::Value(v) => v.convert_to_radix(rdx, rm, cc),
1115            Flavor::NaN(_) => Err(Error::InvalidArgument),
1116            Flavor::Inf(_) => Err(Error::InvalidArgument),
1117        }
1118    }
1119
1120    /// Returns true if `self` is inexact. The function returns false if `self` is Inf or NaN.
1121    pub fn inexact(&self) -> bool {
1122        if let Flavor::Value(v) = &self.inner {
1123            v.inexact()
1124        } else {
1125            false
1126        }
1127    }
1128
1129    /// Marks `self` as inexact if `inexact` is true, or exact otherwise.
1130    /// The function has no effect if `self` is Inf or NaN.
1131    pub fn set_inexact(&mut self, inexact: bool) {
1132        if let Flavor::Value(v) = &mut self.inner {
1133            v.set_inexact(inexact);
1134        }
1135    }
1136
1137    /// Try to round and then set the precision to `p`, given `self` has `s` correct digits in mantissa.
1138    /// The function returns true if rounding succeeded, or if `self` is Inf or NaN.
1139    /// If the fuction returns `false`, `self` is still modified, and should be discarded.
1140    /// In case of an error, `self` will be set to NaN with an associated error.
1141    /// If the precision `p` is incorrect `self` will be set to NaN.
1142    pub fn try_set_precision(&mut self, p: usize, rm: RoundingMode, s: usize) -> bool {
1143        if let Flavor::Value(v) = &mut self.inner {
1144            v.try_set_precision(p, rm, s).unwrap_or_else(|e| {
1145                self.inner = Flavor::NaN(Some(e));
1146                true
1147            })
1148        } else {
1149            true
1150        }
1151    }
1152}
1153
1154impl Clone for BigFloat {
1155    fn clone(&self) -> Self {
1156        match &self.inner {
1157            Flavor::Value(v) => Self::result_to_ext(v.clone(), false, true),
1158            Flavor::Inf(s) => {
1159                if s.is_positive() {
1160                    INF_POS
1161                } else {
1162                    INF_NEG
1163                }
1164            }
1165            Flavor::NaN(err) => Self::nan(*err),
1166        }
1167    }
1168}
1169
1170macro_rules! gen_wrapper_arg {
1171    // function requires self as argument
1172    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1173        #[doc=$comment]
1174        pub fn $fname(&self$(,$arg: $arg_type)*) -> $ret {
1175            match &self.inner {
1176                Flavor::Value(v) => Self::result_to_ext(v.$fname($($arg,)*), v.is_zero(), true),
1177                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1178                Flavor::NaN(err) => Self::nan(*err),
1179            }
1180        }
1181    };
1182}
1183
1184macro_rules! gen_wrapper_arg_rm {
1185    // unwrap error, function requires self as argument
1186    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1187        #[doc=$comment]
1188        pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode) -> $ret {
1189            match &self.inner {
1190                Flavor::Value(v) => {
1191                    Self::result_to_ext(v.$fname($($arg,)* rm), v.is_zero(), true)
1192                },
1193                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1194                Flavor::NaN(err) => Self::nan(*err),
1195            }
1196        }
1197    };
1198}
1199
1200macro_rules! gen_wrapper_arg_rm_cc {
1201    // unwrap error, function requires self as argument
1202    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1203        #[doc=$comment]
1204        pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode, cc: &mut Consts) -> $ret {
1205            match &self.inner {
1206                Flavor::Value(v) => {
1207                    Self::result_to_ext(v.$fname($($arg,)* rm, cc), v.is_zero(), true)
1208                },
1209                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1210                Flavor::NaN(err) => Self::nan(*err),
1211            }
1212        }
1213    };
1214}
1215
1216macro_rules! gen_wrapper_log {
1217    ($comment:literal, $fname:ident, $ret:ty, $pos_inf:block, $neg_inf:block, $($arg:ident, $arg_type:ty),*) => {
1218        #[doc=$comment]
1219        pub fn $fname(&self$(,$arg: $arg_type)*, rm: RoundingMode, cc: &mut Consts) -> $ret {
1220            match &self.inner {
1221                Flavor::Value(v) => {
1222                    if v.is_zero() {
1223                        return INF_NEG;
1224                    }
1225                    Self::result_to_ext(v.$fname($($arg,)* rm, cc), v.is_zero(), true)
1226                },
1227                Flavor::Inf(s) => if s.is_positive() $pos_inf else $neg_inf,
1228                Flavor::NaN(err) => Self::nan(*err),
1229            }
1230        }
1231    };
1232}
1233
1234impl BigFloat {
1235    gen_wrapper_arg!(
1236        "Returns the absolute value of `self`.",
1237        abs,
1238        Self,
1239        { INF_POS },
1240        { INF_POS },
1241    );
1242    gen_wrapper_arg!("Returns the integer part of `self`.", int, Self, { NAN }, {
1243        NAN
1244    },);
1245    gen_wrapper_arg!(
1246        "Returns the fractional part of `self`.",
1247        fract,
1248        Self,
1249        { NAN },
1250        { NAN },
1251    );
1252    gen_wrapper_arg!(
1253        "Returns the smallest integer greater than or equal to `self`.",
1254        ceil,
1255        Self,
1256        { INF_POS },
1257        { INF_NEG },
1258    );
1259    gen_wrapper_arg!(
1260        "Returns the largest integer less than or equal to `self`.",
1261        floor,
1262        Self,
1263        { INF_POS },
1264        { INF_NEG },
1265    );
1266    gen_wrapper_arg_rm!("Returns the rounded number with `n` binary positions in the fractional part of the number using rounding mode `rm`.", 
1267        round,
1268        Self,
1269        { INF_POS },
1270        { INF_NEG },
1271        n,
1272        usize
1273    );
1274    gen_wrapper_arg_rm!(
1275        "Computes the square root of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1276        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1277        sqrt,
1278        Self,
1279        { INF_POS },
1280        { NAN },
1281        p,
1282        usize
1283    );
1284    gen_wrapper_arg_rm!(
1285        "Computes the cube root of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1286        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1287        cbrt,
1288        Self,
1289        { INF_POS },
1290        { INF_NEG },
1291        p,
1292        usize
1293    );
1294    gen_wrapper_log!(
1295        "Computes the natural logarithm of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1296        This function requires constants cache `cc` for computing the result.
1297        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1298        ln,
1299        Self,
1300        { INF_POS },
1301        { NAN },
1302        p,
1303        usize
1304    );
1305    gen_wrapper_log!(
1306        "Computes the logarithm base 2 of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1307        This function requires constants cache `cc` for computing the result.
1308        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1309        log2,
1310        Self,
1311        { INF_POS },
1312        { NAN },
1313        p,
1314        usize
1315    );
1316    gen_wrapper_log!(
1317        "Computes the logarithm base 10 of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1318        This function requires constants cache `cc` for computing the result.
1319        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1320        log10,
1321        Self,
1322        { INF_POS },
1323        { NAN },
1324        p,
1325        usize
1326    );
1327    gen_wrapper_arg_rm_cc!(
1328        "Computes `e` to the power of `self` with precision `p`. The result is rounded using the rounding mode `rm`.
1329        This function requires constants cache `cc` for computing the result.
1330        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1331        exp,
1332        Self,
1333        { INF_POS },
1334        { Self::new(p) },
1335        p,
1336        usize
1337    );
1338
1339    gen_wrapper_arg_rm_cc!(
1340        "Computes the sine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1341        This function requires constants cache `cc` for computing the result.
1342        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1343        sin,
1344        Self,
1345        { NAN },
1346        { NAN },
1347        p,
1348        usize
1349    );
1350    gen_wrapper_arg_rm_cc!(
1351        "Computes the cosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1352        This function requires constants cache `cc` for computing the result.
1353        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1354        cos,
1355        Self,
1356        { NAN },
1357        { NAN },
1358        p,
1359        usize
1360    );
1361    gen_wrapper_arg_rm_cc!(
1362        "Computes the tangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1363        This function requires constants cache `cc` for computing the result.
1364        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1365        tan,
1366        Self,
1367        { NAN },
1368        { NAN },
1369        p,
1370        usize
1371    );
1372    gen_wrapper_arg_rm_cc!(
1373        "Computes the arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1374        This function requires constants cache `cc` for computing the result.
1375        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.", 
1376        asin,
1377        Self,
1378        {NAN},
1379        {NAN},
1380        p,
1381        usize
1382    );
1383    gen_wrapper_arg_rm_cc!(
1384        "Computes the arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1385        This function requires constants cache `cc` for computing the result.
1386        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1387        acos,
1388        Self,
1389        { NAN },
1390        { NAN },
1391        p,
1392        usize
1393    );
1394
1395    gen_wrapper_arg_rm_cc!(
1396        "Computes the hyperbolic sine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1397        This function requires constants cache cc for computing the result. 
1398        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1399        sinh,
1400        Self,
1401        { INF_POS },
1402        { INF_NEG },
1403        p,
1404        usize
1405    );
1406    gen_wrapper_arg_rm_cc!(
1407        "Computes the hyperbolic cosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1408        This function requires constants cache cc for computing the result. 
1409        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1410        cosh,
1411        Self,
1412        { INF_POS },
1413        { INF_POS },
1414        p,
1415        usize
1416    );
1417    gen_wrapper_arg_rm_cc!(
1418        "Computes the hyperbolic arcsine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1419        This function requires constants cache `cc` for computing the result.
1420        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1421        asinh,
1422        Self,
1423        { INF_POS },
1424        { INF_NEG },
1425        p,
1426        usize
1427    );
1428    gen_wrapper_arg_rm_cc!(
1429        "Computes the hyperbolic arccosine of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1430        This function requires constants cache `cc` for computing the result.
1431        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1432        acosh,
1433        Self,
1434        { INF_POS },
1435        { NAN },
1436        p,
1437        usize
1438    );
1439    gen_wrapper_arg_rm_cc!(
1440        "Computes the hyperbolic arctangent of a number with precision `p`. The result is rounded using the rounding mode `rm`.
1441        This function requires constants cache `cc` for computing the result.
1442        Precision is rounded upwards to the word size. The function returns NaN if the precision `p` is incorrect.",
1443        atanh,
1444        Self,
1445        { NAN },
1446        { NAN },
1447        p,
1448        usize
1449    );
1450}
1451
1452macro_rules! impl_int_conv {
1453    ($s:ty, $from_s:ident) => {
1454        impl BigFloat {
1455            /// Constructs BigFloat with precision `p` from an integer value `i`.
1456            /// Precision is rounded upwards to the word size.
1457            /// The function returns NaN if the precision `p` is incorrect.
1458            pub fn $from_s(i: $s, p: usize) -> Self {
1459                Self::result_to_ext(BigFloatNumber::$from_s(i, p), false, true)
1460            }
1461        }
1462
1463        //#[cfg(feature = "std")]
1464        //impl From<$s> for BigFloat {
1465        //    fn from(i: $s) -> Self {
1466        //        let p = GCTX.with(|x| x.borrow().precision);
1467        //        BigFloat::$from_s(i, p)
1468        //    }
1469        //}
1470    };
1471}
1472
1473impl_int_conv!(i8, from_i8);
1474impl_int_conv!(i16, from_i16);
1475impl_int_conv!(i32, from_i32);
1476impl_int_conv!(i64, from_i64);
1477impl_int_conv!(i128, from_i128);
1478
1479impl_int_conv!(u8, from_u8);
1480impl_int_conv!(u16, from_u16);
1481impl_int_conv!(u32, from_u32);
1482impl_int_conv!(u64, from_u64);
1483impl_int_conv!(u128, from_u128);
1484
1485impl From<BigFloatNumber> for BigFloat {
1486    fn from(x: BigFloatNumber) -> Self {
1487        BigFloat {
1488            inner: Flavor::Value(x),
1489        }
1490    }
1491}
1492
1493#[cfg(feature = "std")]
1494use core::{
1495    fmt::{Binary, Display, Formatter, Octal, UpperHex},
1496    str::FromStr,
1497};
1498
1499use core::{cmp::Eq, cmp::Ordering, cmp::PartialEq, cmp::PartialOrd, ops::Neg};
1500
1501impl Neg for BigFloat {
1502    type Output = BigFloat;
1503    fn neg(mut self) -> Self::Output {
1504        self.inv_sign();
1505        self
1506    }
1507}
1508
1509impl Neg for &BigFloat {
1510    type Output = BigFloat;
1511    fn neg(self) -> Self::Output {
1512        let mut ret = self.clone();
1513        ret.inv_sign();
1514        ret
1515    }
1516}
1517
1518//
1519// ordering traits
1520//
1521
1522impl PartialEq for BigFloat {
1523    fn eq(&self, other: &Self) -> bool {
1524        let cmp_result = BigFloat::cmp(self, other);
1525        matches!(cmp_result, Some(0))
1526    }
1527}
1528
1529impl<'a> PartialEq<&'a BigFloat> for BigFloat {
1530    fn eq(&self, other: &&'a BigFloat) -> bool {
1531        let cmp_result = BigFloat::cmp(self, other);
1532        matches!(cmp_result, Some(0))
1533    }
1534}
1535
1536impl Eq for BigFloat {}
1537
1538impl PartialOrd for BigFloat {
1539    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1540        let cmp_result = BigFloat::cmp(self, other);
1541        match cmp_result {
1542            Some(v) => {
1543                if v > 0 {
1544                    Some(Ordering::Greater)
1545                } else if v < 0 {
1546                    Some(Ordering::Less)
1547                } else {
1548                    Some(Ordering::Equal)
1549                }
1550            }
1551            None => None,
1552        }
1553    }
1554}
1555
1556impl<'a> PartialOrd<&'a BigFloat> for BigFloat {
1557    fn partial_cmp(&self, other: &&'a BigFloat) -> Option<Ordering> {
1558        let cmp_result = BigFloat::cmp(self, other);
1559        match cmp_result {
1560            Some(v) => {
1561                if v > 0 {
1562                    Some(Ordering::Greater)
1563                } else if v < 0 {
1564                    Some(Ordering::Less)
1565                } else {
1566                    Some(Ordering::Equal)
1567                }
1568            }
1569            None => None,
1570        }
1571    }
1572}
1573
1574impl Default for BigFloat {
1575    fn default() -> BigFloat {
1576        BigFloat::new(DEFAULT_P)
1577    }
1578}
1579
1580#[cfg(feature = "std")]
1581impl FromStr for BigFloat {
1582    type Err = Error;
1583
1584    /// Returns parsed number or NAN in case of error.
1585    /// The implementation is not available in no_std environment.
1586    fn from_str(src: &str) -> Result<BigFloat, Self::Err> {
1587        let bf = crate::common::consts::TENPOWERS.with(|tp| {
1588            let cc = &mut tp.borrow_mut();
1589            BigFloat::parse(src, Radix::Dec, usize::MAX, RoundingMode::ToEven, cc)
1590        });
1591
1592        if bf.is_nan() {
1593            if let Some(err) = bf.err() {
1594                return Err(err);
1595            }
1596        }
1597
1598        Ok(bf)
1599    }
1600}
1601
1602macro_rules! impl_from {
1603    ($tt:ty, $fn:ident) => {
1604        impl From<$tt> for BigFloat {
1605            fn from(v: $tt) -> Self {
1606                BigFloat::$fn(v, DEFAULT_P)
1607            }
1608        }
1609    };
1610}
1611
1612impl_from!(f32, from_f32);
1613impl_from!(f64, from_f64);
1614impl_from!(i8, from_i8);
1615impl_from!(i16, from_i16);
1616impl_from!(i32, from_i32);
1617impl_from!(i64, from_i64);
1618impl_from!(i128, from_i128);
1619impl_from!(u8, from_u8);
1620impl_from!(u16, from_u16);
1621impl_from!(u32, from_u32);
1622impl_from!(u64, from_u64);
1623impl_from!(u128, from_u128);
1624
1625#[cfg(feature = "std")]
1626macro_rules! impl_format_rdx {
1627    ($trait:ty, $rdx:path) => {
1628        impl $trait for BigFloat {
1629            /// Formats the number.
1630            /// The implementation is not available in no_std environment.
1631            fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), core::fmt::Error> {
1632                crate::common::consts::TENPOWERS.with(|tp| {
1633                    let cc = &mut tp.borrow_mut();
1634                    self.write_str(f, $rdx, RoundingMode::ToEven, cc)
1635                })
1636            }
1637        }
1638    };
1639}
1640
1641#[cfg(feature = "std")]
1642impl_format_rdx!(Binary, Radix::Bin);
1643#[cfg(feature = "std")]
1644impl_format_rdx!(Octal, Radix::Oct);
1645#[cfg(feature = "std")]
1646impl_format_rdx!(Display, Radix::Dec);
1647#[cfg(feature = "std")]
1648impl_format_rdx!(UpperHex, Radix::Hex);
1649
1650/// A trait for conversion with additional arguments.
1651pub trait FromExt<T> {
1652    /// Converts `v` to BigFloat with precision `p` using rounding mode `rm`.
1653    fn from_ext(v: T, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self;
1654}
1655
1656impl<T> FromExt<T> for BigFloat
1657where
1658    BigFloat: From<T>,
1659{
1660    fn from_ext(v: T, p: usize, rm: RoundingMode, _cc: &mut Consts) -> Self {
1661        let mut ret = BigFloat::from(v);
1662        if let Err(err) = ret.set_precision(p, rm) {
1663            BigFloat::nan(Some(err))
1664        } else {
1665            ret
1666        }
1667    }
1668}
1669
1670impl FromExt<&str> for BigFloat {
1671    fn from_ext(v: &str, p: usize, rm: RoundingMode, cc: &mut Consts) -> Self {
1672        BigFloat::parse(v, crate::Radix::Dec, p, rm, cc)
1673    }
1674}
1675
1676#[cfg(test)]
1677mod tests {
1678
1679    use crate::common::util::rand_p;
1680    use crate::defs::DEFAULT_P;
1681    use crate::ext::ONE;
1682    use crate::ext::TWO;
1683    use crate::BigFloat;
1684    use crate::Consts;
1685    use crate::Error;
1686    use crate::Radix;
1687    use crate::Sign;
1688    use crate::Word;
1689    use crate::INF_NEG;
1690    use crate::INF_POS;
1691    use crate::NAN;
1692    use crate::{defs::RoundingMode, WORD_BIT_SIZE};
1693
1694    use core::num::FpCategory;
1695    #[cfg(feature = "std")]
1696    use std::str::FromStr;
1697
1698    #[cfg(not(feature = "std"))]
1699    use alloc::format;
1700
1701    #[cfg(target_pointer_width = "32")]
1702    #[test]
1703    fn test_decimal_formatting_round_trip() {
1704        // Regression test: on 32-bit targets, decimal formatting must produce a string
1705        // that parses back to the original value without losing precision.
1706        let mut cc = Consts::new().unwrap();
1707        let p = 53;
1708        let rm = RoundingMode::ToEven;
1709        let value = BigFloat::parse("1.0", Radix::Dec, p, rm, &mut cc);
1710
1711        let formatted = value.format(Radix::Dec, rm, &mut cc).unwrap();
1712        assert_eq!(formatted, "1.e+0");
1713
1714        let reparsed = BigFloat::parse(&formatted, Radix::Dec, p, rm, &mut cc);
1715        assert_eq!(reparsed, value);
1716    }
1717
1718    #[test]
1719    fn test_ext() {
1720        let rm = RoundingMode::ToOdd;
1721        let mut cc = Consts::new().unwrap();
1722
1723        // Inf & NaN
1724        let d1 = BigFloat::from_u8(1, rand_p());
1725        assert!(!d1.is_inf());
1726        assert!(!d1.is_nan());
1727        assert!(!d1.is_inf_pos());
1728        assert!(!d1.is_inf_neg());
1729        assert!(d1.is_positive());
1730
1731        let mut d1 = d1.div(&BigFloat::new(rand_p()), rand_p(), rm);
1732        assert!(d1.is_inf());
1733        assert!(!d1.is_nan());
1734        assert!(d1.is_inf_pos());
1735        assert!(!d1.is_inf_neg());
1736        assert!(d1.is_positive());
1737
1738        d1.inv_sign();
1739        assert!(d1.is_inf());
1740        assert!(!d1.is_nan());
1741        assert!(!d1.is_inf_pos());
1742        assert!(d1.is_inf_neg());
1743        assert!(d1.is_negative());
1744
1745        let d1 = BigFloat::new(rand_p()).div(&BigFloat::new(rand_p()), rand_p(), rm);
1746        assert!(!d1.is_inf());
1747        assert!(d1.is_nan());
1748        assert!(!d1.is_inf_pos());
1749        assert!(!d1.is_inf_neg());
1750        assert!(d1.sign().is_none());
1751
1752        for _ in 0..1000 {
1753            let i = rand::random::<i64>();
1754            let d1 = BigFloat::from_i64(i, rand_p());
1755            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1756            assert!(d1.cmp(&n1) == Some(0));
1757
1758            let i = rand::random::<u64>();
1759            let d1 = BigFloat::from_u64(i, rand_p());
1760            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1761            assert!(d1.cmp(&n1) == Some(0));
1762
1763            let i = rand::random::<i128>();
1764            let d1 = BigFloat::from_i128(i, rand_p());
1765            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1766            assert!(d1.cmp(&n1) == Some(0));
1767
1768            let i = rand::random::<u128>();
1769            let d1 = BigFloat::from_u128(i, rand_p());
1770            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1771            assert!(d1.cmp(&n1) == Some(0));
1772        }
1773
1774        assert!(ONE.exponent().is_some());
1775        assert!(INF_POS.exponent().is_none());
1776        assert!(INF_NEG.exponent().is_none());
1777        assert!(NAN.exponent().is_none());
1778
1779        assert!(ONE.as_raw_parts().is_some());
1780        assert!(INF_POS.as_raw_parts().is_none());
1781        assert!(INF_NEG.as_raw_parts().is_none());
1782        assert!(NAN.as_raw_parts().is_none());
1783
1784        assert!(ONE.add(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
1785        assert!(ONE.add(&INF_POS, rand_p(), rm).is_inf_pos());
1786        assert!(INF_POS.add(&ONE, rand_p(), rm).is_inf_pos());
1787        assert!(ONE.add(&INF_NEG, rand_p(), rm).is_inf_neg());
1788        assert!(INF_NEG.add(&ONE, rand_p(), rm).is_inf_neg());
1789        assert!(INF_POS.add(&INF_POS, rand_p(), rm).is_inf_pos());
1790        assert!(INF_POS.add(&INF_NEG, rand_p(), rm).is_nan());
1791        assert!(INF_NEG.add(&INF_NEG, rand_p(), rm).is_inf_neg());
1792        assert!(INF_NEG.add(&INF_POS, rand_p(), rm).is_nan());
1793
1794        assert!(ONE.add_full_prec(&ONE).cmp(&TWO) == Some(0));
1795        assert!(ONE.add_full_prec(&INF_POS).is_inf_pos());
1796        assert!(INF_POS.add_full_prec(&ONE).is_inf_pos());
1797        assert!(ONE.add_full_prec(&INF_NEG).is_inf_neg());
1798        assert!(INF_NEG.add_full_prec(&ONE).is_inf_neg());
1799        assert!(INF_POS.add_full_prec(&INF_POS).is_inf_pos());
1800        assert!(INF_POS.add_full_prec(&INF_NEG).is_nan());
1801        assert!(INF_NEG.add_full_prec(&INF_NEG).is_inf_neg());
1802        assert!(INF_NEG.add_full_prec(&INF_POS).is_nan());
1803
1804        assert!(ONE.sub_full_prec(&ONE).is_zero());
1805        assert!(ONE.sub_full_prec(&INF_POS).is_inf_neg());
1806        assert!(INF_POS.sub_full_prec(&ONE).is_inf_pos());
1807        assert!(ONE.sub_full_prec(&INF_NEG).is_inf_pos());
1808        assert!(INF_NEG.sub_full_prec(&ONE).is_inf_neg());
1809        assert!(INF_POS.sub_full_prec(&INF_POS).is_nan());
1810        assert!(INF_POS.sub_full_prec(&INF_NEG).is_inf_pos());
1811        assert!(INF_NEG.sub_full_prec(&INF_NEG).is_nan());
1812        assert!(INF_NEG.sub_full_prec(&INF_POS).is_inf_neg());
1813
1814        assert!(ONE.mul_full_prec(&ONE).cmp(&ONE) == Some(0));
1815        assert!(ONE.mul_full_prec(&INF_POS).is_inf_pos());
1816        assert!(INF_POS.mul_full_prec(&ONE).is_inf_pos());
1817        assert!(ONE.mul_full_prec(&INF_NEG).is_inf_neg());
1818        assert!(INF_NEG.mul_full_prec(&ONE).is_inf_neg());
1819        assert!(INF_POS.mul_full_prec(&INF_POS).is_inf_pos());
1820        assert!(INF_POS.mul_full_prec(&INF_NEG).is_inf_neg());
1821        assert!(INF_NEG.mul_full_prec(&INF_NEG).is_inf_pos());
1822        assert!(INF_NEG.mul_full_prec(&INF_POS).is_inf_neg());
1823
1824        assert!(TWO.sub(&ONE, rand_p(), rm).cmp(&ONE) == Some(0));
1825        assert!(ONE.sub(&INF_POS, rand_p(), rm).is_inf_neg());
1826        assert!(INF_POS.sub(&ONE, rand_p(), rm).is_inf_pos());
1827        assert!(ONE.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
1828        assert!(INF_NEG.sub(&ONE, rand_p(), rm).is_inf_neg());
1829        assert!(INF_POS.sub(&INF_POS, rand_p(), rm).is_nan());
1830        assert!(INF_POS.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
1831        assert!(INF_NEG.sub(&INF_NEG, rand_p(), rm).is_nan());
1832        assert!(INF_NEG.sub(&INF_POS, rand_p(), rm).is_inf_neg());
1833
1834        assert!(TWO.mul(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
1835        assert!(ONE.mul(&INF_POS, rand_p(), rm).is_inf_pos());
1836        assert!(INF_POS.mul(&ONE, rand_p(), rm).is_inf_pos());
1837        assert!(ONE.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
1838        assert!(INF_NEG.mul(&ONE, rand_p(), rm).is_inf_neg());
1839        assert!(ONE.neg().mul(&INF_POS, rand_p(), rm).is_inf_neg());
1840        assert!(ONE.neg().mul(&INF_NEG, rand_p(), rm).is_inf_pos());
1841        assert!(INF_POS.mul(&ONE.neg(), rand_p(), rm).is_inf_neg());
1842        assert!(INF_NEG.mul(&ONE.neg(), rand_p(), rm).is_inf_pos());
1843        assert!(INF_POS.mul(&INF_POS, rand_p(), rm).is_inf_pos());
1844        assert!(INF_POS.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
1845        assert!(INF_NEG.mul(&INF_NEG, rand_p(), rm).is_inf_pos());
1846        assert!(INF_NEG.mul(&INF_POS, rand_p(), rm).is_inf_neg());
1847        assert!(INF_POS.mul(&BigFloat::new(rand_p()), rand_p(), rm).is_nan());
1848        assert!(INF_NEG.mul(&BigFloat::new(rand_p()), rand_p(), rm).is_nan());
1849        assert!(BigFloat::new(rand_p()).mul(&INF_POS, rand_p(), rm).is_nan());
1850        assert!(BigFloat::new(rand_p()).mul(&INF_NEG, rand_p(), rm).is_nan());
1851
1852        assert!(TWO.div(&TWO, rand_p(), rm).cmp(&ONE) == Some(0));
1853        assert!(TWO.div(&INF_POS, rand_p(), rm).is_zero());
1854        assert!(INF_POS.div(&TWO, rand_p(), rm).is_inf_pos());
1855        assert!(TWO.div(&INF_NEG, rand_p(), rm).is_zero());
1856        assert!(INF_NEG.div(&TWO, rand_p(), rm).is_inf_neg());
1857        assert!(TWO.neg().div(&INF_POS, rand_p(), rm).is_zero());
1858        assert!(TWO.neg().div(&INF_NEG, rand_p(), rm).is_zero());
1859        assert!(INF_POS.div(&TWO.neg(), rand_p(), rm).is_inf_neg());
1860        assert!(INF_NEG.div(&TWO.neg(), rand_p(), rm).is_inf_pos());
1861        assert!(INF_POS.div(&INF_POS, rand_p(), rm).is_nan());
1862        assert!(INF_POS.div(&INF_NEG, rand_p(), rm).is_nan());
1863        assert!(INF_NEG.div(&INF_NEG, rand_p(), rm).is_nan());
1864        assert!(INF_NEG.div(&INF_POS, rand_p(), rm).is_nan());
1865        assert!(INF_POS
1866            .div(&BigFloat::new(rand_p()), rand_p(), rm)
1867            .is_inf_pos());
1868        assert!(INF_NEG
1869            .div(&BigFloat::new(rand_p()), rand_p(), rm)
1870            .is_inf_neg());
1871        assert!(BigFloat::new(rand_p())
1872            .div(&INF_POS, rand_p(), rm)
1873            .is_zero());
1874        assert!(BigFloat::new(rand_p())
1875            .div(&INF_NEG, rand_p(), rm)
1876            .is_zero());
1877
1878        assert!(TWO.rem(&TWO).is_zero());
1879        assert!(TWO.rem(&INF_POS).cmp(&TWO) == Some(0));
1880        assert!(INF_POS.rem(&TWO).is_nan());
1881        assert!(TWO.rem(&INF_NEG).cmp(&TWO) == Some(0));
1882        assert!(INF_NEG.rem(&TWO).is_nan());
1883        assert!(TWO.neg().rem(&INF_POS).cmp(&TWO.neg()) == Some(0));
1884        assert!(TWO.neg().rem(&INF_NEG).cmp(&TWO.neg()) == Some(0));
1885        assert!(INF_POS.rem(&TWO.neg()).is_nan());
1886        assert!(INF_NEG.rem(&TWO.neg()).is_nan());
1887        assert!(INF_POS.rem(&INF_POS).is_nan());
1888        assert!(INF_POS.rem(&INF_NEG).is_nan());
1889        assert!(INF_NEG.rem(&INF_NEG).is_nan());
1890        assert!(INF_NEG.rem(&INF_POS).is_nan());
1891        assert!(INF_POS.rem(&BigFloat::new(rand_p())).is_nan());
1892        assert!(INF_NEG.rem(&BigFloat::new(rand_p())).is_nan());
1893        assert!(BigFloat::new(rand_p()).rem(&INF_POS).is_zero());
1894        assert!(BigFloat::new(rand_p()).rem(&INF_NEG).is_zero());
1895
1896        for op in [BigFloat::add, BigFloat::sub, BigFloat::mul, BigFloat::div] {
1897            assert!(op(&NAN, &ONE, rand_p(), rm).is_nan());
1898            assert!(op(&ONE, &NAN, rand_p(), rm).is_nan());
1899            assert!(op(&NAN, &INF_POS, rand_p(), rm).is_nan());
1900            assert!(op(&INF_POS, &NAN, rand_p(), rm).is_nan());
1901            assert!(op(&NAN, &INF_NEG, rand_p(), rm).is_nan());
1902            assert!(op(&INF_NEG, &NAN, rand_p(), rm).is_nan());
1903            assert!(op(&NAN, &NAN, rand_p(), rm).is_nan());
1904        }
1905
1906        assert!(BigFloat::rem(&NAN, &ONE).is_nan());
1907        assert!(BigFloat::rem(&ONE, &NAN).is_nan());
1908        assert!(BigFloat::rem(&NAN, &INF_POS).is_nan());
1909        assert!(BigFloat::rem(&INF_POS, &NAN).is_nan());
1910        assert!(BigFloat::rem(&NAN, &INF_NEG).is_nan());
1911        assert!(BigFloat::rem(&INF_NEG, &NAN).is_nan());
1912        assert!(BigFloat::rem(&NAN, &NAN).is_nan());
1913
1914        for op in [BigFloat::add_full_prec, BigFloat::sub_full_prec, BigFloat::mul_full_prec] {
1915            assert!(op(&NAN, &ONE).is_nan());
1916            assert!(op(&ONE, &NAN).is_nan());
1917            assert!(op(&NAN, &INF_POS).is_nan());
1918            assert!(op(&INF_POS, &NAN).is_nan());
1919            assert!(op(&NAN, &INF_NEG).is_nan());
1920            assert!(op(&INF_NEG, &NAN).is_nan());
1921            assert!(op(&NAN, &NAN).is_nan());
1922        }
1923
1924        assert!(ONE.cmp(&ONE).unwrap() == 0);
1925        assert!(ONE.cmp(&INF_POS).unwrap() < 0);
1926        assert!(INF_POS.cmp(&ONE).unwrap() > 0);
1927        assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
1928        assert!(ONE.cmp(&INF_NEG).unwrap() > 0);
1929        assert!(INF_NEG.cmp(&ONE).unwrap() < 0);
1930        assert!(INF_NEG.cmp(&INF_NEG).unwrap() == 0);
1931        assert!(INF_POS.cmp(&INF_NEG).unwrap() > 0);
1932        assert!(INF_NEG.cmp(&INF_POS).unwrap() < 0);
1933        assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
1934        assert!(ONE.cmp(&NAN).is_none());
1935        assert!(NAN.cmp(&ONE).is_none());
1936        assert!(INF_POS.cmp(&NAN).is_none());
1937        assert!(NAN.cmp(&INF_POS).is_none());
1938        assert!(INF_NEG.cmp(&NAN).is_none());
1939        assert!(NAN.cmp(&INF_NEG).is_none());
1940        assert!(NAN.cmp(&NAN).is_none());
1941
1942        assert!(ONE.abs_cmp(&ONE).unwrap() == 0);
1943        assert!(ONE.abs_cmp(&INF_POS).unwrap() < 0);
1944        assert!(INF_POS.abs_cmp(&ONE).unwrap() > 0);
1945        assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
1946        assert!(ONE.abs_cmp(&INF_NEG).unwrap() < 0);
1947        assert!(INF_NEG.abs_cmp(&ONE).unwrap() > 0);
1948        assert!(INF_NEG.abs_cmp(&INF_NEG).unwrap() == 0);
1949        assert!(INF_POS.abs_cmp(&INF_NEG).unwrap() == 0);
1950        assert!(INF_NEG.abs_cmp(&INF_POS).unwrap() == 0);
1951        assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
1952        assert!(ONE.abs_cmp(&NAN).is_none());
1953        assert!(NAN.abs_cmp(&ONE).is_none());
1954        assert!(INF_POS.abs_cmp(&NAN).is_none());
1955        assert!(NAN.abs_cmp(&INF_POS).is_none());
1956        assert!(INF_NEG.abs_cmp(&NAN).is_none());
1957        assert!(NAN.abs_cmp(&INF_NEG).is_none());
1958        assert!(NAN.abs_cmp(&NAN).is_none());
1959
1960        assert!(ONE.is_positive());
1961        assert!(!ONE.is_negative());
1962
1963        assert!(ONE.neg().is_negative());
1964        assert!(!ONE.neg().is_positive());
1965        assert!(!INF_POS.is_negative());
1966        assert!(INF_POS.is_positive());
1967        assert!(INF_NEG.is_negative());
1968        assert!(!INF_NEG.is_positive());
1969        assert!(!NAN.is_positive());
1970        assert!(!NAN.is_negative());
1971
1972        assert!(ONE.pow(&ONE, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1973        assert!(BigFloat::new(DEFAULT_P)
1974            .pow(&INF_POS, rand_p(), rm, &mut cc)
1975            .is_zero());
1976        assert!(BigFloat::new(DEFAULT_P)
1977            .pow(&INF_NEG, rand_p(), rm, &mut cc)
1978            .is_zero());
1979        assert!(ONE.pow(&INF_POS, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1980        assert!(ONE.pow(&INF_NEG, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1981        assert!(TWO.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
1982        assert!(TWO.pow(&INF_NEG, rand_p(), rm, &mut cc).is_inf_neg());
1983        assert!(INF_POS.pow(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
1984        assert!(INF_NEG.pow(&ONE, rand_p(), rm, &mut cc).is_inf_neg());
1985        assert!(INF_NEG.pow(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
1986        assert!(INF_NEG
1987            .pow(&BigFloat::from_f64(10.2, DEFAULT_P), rand_p(), rm, &mut cc)
1988            .is_inf_pos());
1989        assert!(INF_NEG
1990            .pow(&BigFloat::from_f64(3.0, DEFAULT_P), rand_p(), rm, &mut cc)
1991            .is_inf_neg());
1992        assert!(INF_POS.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
1993        assert!(INF_NEG.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
1994        assert!(
1995            INF_POS
1996                .pow(&BigFloat::new(DEFAULT_P), rand_p(), rm, &mut cc)
1997                .cmp(&ONE)
1998                == Some(0)
1999        );
2000        assert!(
2001            INF_NEG
2002                .pow(&BigFloat::new(DEFAULT_P), rand_p(), rm, &mut cc)
2003                .cmp(&ONE)
2004                == Some(0)
2005        );
2006        assert!(INF_POS.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
2007        assert!(INF_NEG.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
2008        assert!(INF_POS.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
2009        assert!(INF_NEG.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
2010
2011        let half = ONE.div(&TWO, rand_p(), rm);
2012        assert!(TWO.log(&TWO, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
2013        assert!(TWO.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
2014        assert!(TWO.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2015        assert!(INF_POS.log(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
2016        assert!(INF_NEG.log(&TWO, rand_p(), rm, &mut cc).is_nan());
2017        assert!(half.log(&half, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
2018        assert!(half.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
2019        assert!(half.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2020        assert!(INF_POS.log(&half, rand_p(), rm, &mut cc).is_inf_neg());
2021        assert!(INF_NEG.log(&half, rand_p(), rm, &mut cc).is_nan());
2022        assert!(INF_POS.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2023        assert!(INF_POS.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2024        assert!(INF_NEG.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2025        assert!(INF_NEG.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2026        assert!(TWO.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
2027        assert!(half.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
2028        assert!(ONE.log(&ONE, rand_p(), rm, &mut cc).is_nan());
2029
2030        assert!(BigFloat::from_f32(f32::NAN, DEFAULT_P).is_nan());
2031        assert!(BigFloat::from_f32(f32::INFINITY, DEFAULT_P).is_inf_pos());
2032        assert!(BigFloat::from_f32(f32::NEG_INFINITY, DEFAULT_P).is_inf_neg());
2033        assert!(!BigFloat::from_f32(1.0, DEFAULT_P).is_nan());
2034        assert!(BigFloat::from_f64(f64::NAN, DEFAULT_P).is_nan());
2035        assert!(BigFloat::from_f64(f64::INFINITY, DEFAULT_P).is_inf_pos());
2036        assert!(BigFloat::from_f64(f64::NEG_INFINITY, DEFAULT_P).is_inf_neg());
2037        assert!(!BigFloat::from_f64(1.0, DEFAULT_P).is_nan());
2038
2039        assert!(ONE.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2040        assert!(NAN.pow(&ONE, rand_p(), rm, &mut cc).is_nan());
2041        assert!(INF_POS.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2042        assert!(NAN.pow(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2043        assert!(INF_NEG.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2044        assert!(NAN.pow(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2045        assert!(NAN.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2046
2047        assert!(NAN.powi(2, rand_p(), rm).is_nan());
2048        assert!(NAN.powi(0, rand_p(), rm).is_nan());
2049        assert!(INF_POS.powi(2, rand_p(), rm).is_inf_pos());
2050        assert!(INF_POS.powi(3, rand_p(), rm).is_inf_pos());
2051        assert!(INF_NEG.powi(4, rand_p(), rm).is_inf_pos());
2052        assert!(INF_NEG.powi(5, rand_p(), rm).is_inf_neg());
2053        assert!(INF_POS.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
2054        assert!(INF_NEG.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
2055
2056        assert!(TWO.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2057        assert!(NAN.log(&TWO, rand_p(), rm, &mut cc).is_nan());
2058        assert!(INF_POS.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2059        assert!(NAN.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2060        assert!(INF_NEG.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2061        assert!(NAN.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2062        assert!(NAN.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2063
2064        assert!(INF_NEG.abs().is_inf_pos());
2065        assert!(INF_POS.abs().is_inf_pos());
2066        assert!(NAN.abs().is_nan());
2067
2068        assert!(INF_NEG.int().is_nan());
2069        assert!(INF_POS.int().is_nan());
2070        assert!(NAN.int().is_nan());
2071
2072        assert!(INF_NEG.fract().is_nan());
2073        assert!(INF_POS.fract().is_nan());
2074        assert!(NAN.fract().is_nan());
2075
2076        assert!(INF_NEG.ceil().is_inf_neg());
2077        assert!(INF_POS.ceil().is_inf_pos());
2078        assert!(NAN.ceil().is_nan());
2079
2080        assert!(INF_NEG.floor().is_inf_neg());
2081        assert!(INF_POS.floor().is_inf_pos());
2082        assert!(NAN.floor().is_nan());
2083
2084        for rm in [
2085            RoundingMode::Up,
2086            RoundingMode::Down,
2087            RoundingMode::ToZero,
2088            RoundingMode::FromZero,
2089            RoundingMode::ToEven,
2090            RoundingMode::ToOdd,
2091        ] {
2092            assert!(INF_NEG.round(0, rm).is_inf_neg());
2093            assert!(INF_POS.round(0, rm).is_inf_pos());
2094            assert!(NAN.round(0, rm).is_nan());
2095        }
2096
2097        assert!(INF_NEG.sqrt(rand_p(), rm).is_nan());
2098        assert!(INF_POS.sqrt(rand_p(), rm).is_inf_pos());
2099        assert!(NAN.sqrt(rand_p(), rm).is_nan());
2100
2101        assert!(INF_NEG.cbrt(rand_p(), rm).is_inf_neg());
2102        assert!(INF_POS.cbrt(rand_p(), rm).is_inf_pos());
2103        assert!(NAN.cbrt(rand_p(), rm).is_nan());
2104
2105        for op in [BigFloat::ln, BigFloat::log2, BigFloat::log10] {
2106            assert!(op(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2107            assert!(op(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
2108            assert!(op(&NAN, rand_p(), rm, &mut cc).is_nan());
2109        }
2110
2111        assert!(INF_NEG.exp(rand_p(), rm, &mut cc).is_zero());
2112        assert!(INF_POS.exp(rand_p(), rm, &mut cc).is_inf_pos());
2113        assert!(NAN.exp(rand_p(), rm, &mut cc).is_nan());
2114
2115        assert!(INF_NEG.sin(rand_p(), rm, &mut cc).is_nan());
2116        assert!(INF_POS.sin(rand_p(), rm, &mut cc).is_nan());
2117        assert!(NAN.sin(rand_p(), rm, &mut cc).is_nan());
2118
2119        assert!(INF_NEG.cos(rand_p(), rm, &mut cc).is_nan());
2120        assert!(INF_POS.cos(rand_p(), rm, &mut cc).is_nan());
2121        assert!(NAN.cos(rand_p(), rm, &mut cc).is_nan());
2122
2123        assert!(INF_NEG.tan(rand_p(), rm, &mut cc).is_nan());
2124        assert!(INF_POS.tan(rand_p(), rm, &mut cc).is_nan());
2125        assert!(NAN.tan(rand_p(), rm, &mut cc).is_nan());
2126
2127        assert!(INF_NEG.asin(rand_p(), rm, &mut cc).is_nan());
2128        assert!(INF_POS.asin(rand_p(), rm, &mut cc).is_nan());
2129        assert!(NAN.asin(rand_p(), rm, &mut cc).is_nan());
2130
2131        assert!(INF_NEG.acos(rand_p(), rm, &mut cc).is_nan());
2132        assert!(INF_POS.acos(rand_p(), rm, &mut cc).is_nan());
2133        assert!(NAN.acos(rand_p(), rm, &mut cc).is_nan());
2134
2135        let p = rand_p();
2136        let mut half_pi: BigFloat = cc.pi_num(p, rm).unwrap().into();
2137        half_pi.set_exponent(1);
2138        assert!(INF_NEG.atan(p, rm, &mut cc).cmp(&half_pi.neg()) == Some(0));
2139        assert!(INF_POS.atan(p, rm, &mut cc).cmp(&half_pi) == Some(0));
2140        assert!(NAN.atan(rand_p(), rm, &mut cc).is_nan());
2141
2142        assert!(INF_NEG.sinh(rand_p(), rm, &mut cc).is_inf_neg());
2143        assert!(INF_POS.sinh(rand_p(), rm, &mut cc).is_inf_pos());
2144        assert!(NAN.sinh(rand_p(), rm, &mut cc).is_nan());
2145
2146        assert!(INF_NEG.cosh(rand_p(), rm, &mut cc).is_inf_pos());
2147        assert!(INF_POS.cosh(rand_p(), rm, &mut cc).is_inf_pos());
2148        assert!(NAN.cosh(rand_p(), rm, &mut cc).is_nan());
2149
2150        assert!(INF_NEG.tanh(rand_p(), rm, &mut cc).cmp(&ONE.neg()) == Some(0));
2151        assert!(INF_POS.tanh(rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
2152        assert!(NAN.tanh(rand_p(), rm, &mut cc).is_nan());
2153
2154        assert!(INF_NEG.asinh(rand_p(), rm, &mut cc).is_inf_neg());
2155        assert!(INF_POS.asinh(rand_p(), rm, &mut cc).is_inf_pos());
2156        assert!(NAN.asinh(rand_p(), rm, &mut cc).is_nan());
2157
2158        assert!(INF_NEG.acosh(rand_p(), rm, &mut cc).is_nan());
2159        assert!(INF_POS.acosh(rand_p(), rm, &mut cc).is_inf_pos());
2160        assert!(NAN.acosh(rand_p(), rm, &mut cc).is_nan());
2161
2162        assert!(INF_NEG.atanh(rand_p(), rm, &mut cc).is_nan());
2163        assert!(INF_POS.atanh(rand_p(), rm, &mut cc).is_nan());
2164        assert!(NAN.atanh(rand_p(), rm, &mut cc).is_nan());
2165
2166        assert!(INF_NEG.reciprocal(rand_p(), rm).is_zero());
2167        assert!(INF_POS.reciprocal(rand_p(), rm).is_zero());
2168        assert!(NAN.reciprocal(rand_p(), rm).is_nan());
2169
2170        assert!(TWO.signum().cmp(&ONE) == Some(0));
2171        assert!(TWO.neg().signum().cmp(&ONE.neg()) == Some(0));
2172        assert!(INF_POS.signum().cmp(&ONE) == Some(0));
2173        assert!(INF_NEG.signum().cmp(&ONE.neg()) == Some(0));
2174        assert!(NAN.signum().is_nan());
2175
2176        let d1 = ONE.clone();
2177        assert!(d1.exponent() == Some(1));
2178        let words: &[Word] = {
2179            #[cfg(not(target_pointer_width = "32"))]
2180            {
2181                &[0, 0x8000000000000000]
2182            }
2183            #[cfg(target_pointer_width = "32")]
2184            {
2185                &[0, 0, 0, 0x80000000]
2186            }
2187        };
2188
2189        assert!(d1.mantissa_digits() == Some(words));
2190        assert!(d1.mantissa_max_bit_len() == Some(DEFAULT_P));
2191        assert!(d1.precision() == Some(DEFAULT_P));
2192        assert!(d1.sign() == Some(Sign::Pos));
2193
2194        assert!(INF_POS.exponent().is_none());
2195        assert!(INF_POS.mantissa_digits().is_none());
2196        assert!(INF_POS.mantissa_max_bit_len().is_none());
2197        assert!(INF_POS.precision().is_none());
2198        assert!(INF_POS.sign() == Some(Sign::Pos));
2199
2200        assert!(INF_NEG.exponent().is_none());
2201        assert!(INF_NEG.mantissa_digits().is_none());
2202        assert!(INF_NEG.mantissa_max_bit_len().is_none());
2203        assert!(INF_NEG.precision().is_none());
2204        assert!(INF_NEG.sign() == Some(Sign::Neg));
2205
2206        assert!(NAN.exponent().is_none());
2207        assert!(NAN.mantissa_digits().is_none());
2208        assert!(NAN.mantissa_max_bit_len().is_none());
2209        assert!(NAN.precision().is_none());
2210        assert!(NAN.sign().is_none());
2211
2212        INF_POS.clone().set_exponent(1);
2213        INF_POS.clone().set_precision(1, rm).unwrap();
2214        INF_POS.clone().set_sign(Sign::Pos);
2215
2216        INF_NEG.clone().set_exponent(1);
2217        INF_NEG.clone().set_precision(1, rm).unwrap();
2218        INF_NEG.clone().set_sign(Sign::Pos);
2219
2220        NAN.clone().set_exponent(1);
2221        NAN.clone().set_precision(1, rm).unwrap();
2222        NAN.clone().set_sign(Sign::Pos);
2223
2224        assert!(INF_POS.min(&ONE).cmp(&ONE) == Some(0));
2225        assert!(INF_NEG.min(&ONE).is_inf_neg());
2226        assert!(NAN.min(&ONE).is_nan());
2227        assert!(ONE.min(&INF_POS).cmp(&ONE) == Some(0));
2228        assert!(ONE.min(&INF_NEG).is_inf_neg());
2229        assert!(ONE.min(&NAN).is_nan());
2230        assert!(NAN.min(&INF_POS).is_nan());
2231        assert!(NAN.min(&INF_NEG).is_nan());
2232        assert!(NAN.min(&NAN).is_nan());
2233        assert!(INF_NEG.min(&INF_POS).is_inf_neg());
2234        assert!(INF_POS.min(&INF_NEG).is_inf_neg());
2235        assert!(INF_POS.min(&INF_POS).is_inf_pos());
2236        assert!(INF_NEG.min(&INF_NEG).is_inf_neg());
2237
2238        assert!(INF_POS.max(&ONE).is_inf_pos());
2239        assert!(INF_NEG.max(&ONE).cmp(&ONE) == Some(0));
2240        assert!(NAN.max(&ONE).is_nan());
2241        assert!(ONE.max(&INF_POS).is_inf_pos());
2242        assert!(ONE.max(&INF_NEG).cmp(&ONE) == Some(0));
2243        assert!(ONE.max(&NAN).is_nan());
2244        assert!(NAN.max(&INF_POS).is_nan());
2245        assert!(NAN.max(&INF_NEG).is_nan());
2246        assert!(NAN.max(&NAN).is_nan());
2247        assert!(INF_NEG.max(&INF_POS).is_inf_pos());
2248        assert!(INF_POS.max(&INF_NEG).is_inf_pos());
2249        assert!(INF_POS.max(&INF_POS).is_inf_pos());
2250        assert!(INF_NEG.max(&INF_NEG).is_inf_neg());
2251
2252        assert!(ONE.clamp(&ONE.neg(), &TWO).cmp(&ONE) == Some(0));
2253        assert!(ONE.clamp(&TWO, &ONE).is_nan());
2254        assert!(ONE.clamp(&INF_POS, &ONE).is_nan());
2255        assert!(ONE.clamp(&TWO, &INF_NEG).is_nan());
2256        assert!(ONE.neg().clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
2257        assert!(TWO.clamp(&ONE.neg(), &ONE).cmp(&ONE) == Some(0));
2258        assert!(INF_POS.clamp(&ONE, &TWO).cmp(&TWO) == Some(0));
2259        assert!(INF_POS.clamp(&ONE, &INF_POS).is_inf_pos());
2260        assert!(INF_POS.clamp(&INF_NEG, &ONE).cmp(&ONE) == Some(0));
2261        assert!(INF_POS.clamp(&NAN, &INF_POS).is_nan());
2262        assert!(INF_POS.clamp(&ONE, &NAN).is_nan());
2263        assert!(INF_POS.clamp(&NAN, &NAN).is_nan());
2264        assert!(INF_NEG.clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
2265        assert!(INF_NEG.clamp(&ONE, &INF_POS).cmp(&ONE) == Some(0));
2266        assert!(INF_NEG.clamp(&INF_NEG, &ONE).is_inf_neg());
2267        assert!(INF_NEG.clamp(&NAN, &INF_POS).is_nan());
2268        assert!(INF_NEG.clamp(&ONE, &NAN).is_nan());
2269        assert!(INF_NEG.clamp(&NAN, &NAN).is_nan());
2270        assert!(NAN.clamp(&ONE, &TWO).is_nan());
2271        assert!(NAN.clamp(&NAN, &TWO).is_nan());
2272        assert!(NAN.clamp(&ONE, &NAN).is_nan());
2273        assert!(NAN.clamp(&NAN, &NAN).is_nan());
2274        assert!(NAN.clamp(&INF_NEG, &INF_POS).is_nan());
2275
2276        assert!(BigFloat::min_positive(DEFAULT_P).classify() == FpCategory::Subnormal);
2277        assert!(INF_POS.classify() == FpCategory::Infinite);
2278        assert!(INF_NEG.classify() == FpCategory::Infinite);
2279        assert!(NAN.classify() == FpCategory::Nan);
2280        assert!(ONE.classify() == FpCategory::Normal);
2281
2282        assert!(!INF_POS.is_subnormal());
2283        assert!(!INF_NEG.is_subnormal());
2284        assert!(!NAN.is_subnormal());
2285        assert!(BigFloat::min_positive(DEFAULT_P).is_subnormal());
2286        assert!(!BigFloat::min_positive_normal(DEFAULT_P).is_subnormal());
2287        assert!(!BigFloat::max_value(DEFAULT_P).is_subnormal());
2288        assert!(!BigFloat::min_value(DEFAULT_P).is_subnormal());
2289
2290        let n1 = BigFloat::convert_from_radix(
2291            Sign::Pos,
2292            &[],
2293            0,
2294            Radix::Dec,
2295            usize::MAX - 1,
2296            RoundingMode::None,
2297            &mut cc,
2298        );
2299        assert!(n1.is_nan());
2300        assert!(n1.err() == Some(Error::InvalidArgument));
2301
2302        assert!(
2303            n1.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
2304                == Err(Error::InvalidArgument)
2305        );
2306        assert!(
2307            INF_POS.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
2308                == Err(Error::InvalidArgument)
2309        );
2310        assert!(
2311            INF_NEG.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
2312                == Err(Error::InvalidArgument)
2313        );
2314    }
2315
2316    #[cfg(feature = "std")]
2317    #[test]
2318    fn test_ops_std() {
2319        let mut cc = Consts::new().unwrap();
2320
2321        let d1 = BigFloat::parse(
2322            "0.0123456789012345678901234567890123456789",
2323            Radix::Dec,
2324            DEFAULT_P,
2325            RoundingMode::None,
2326            &mut cc,
2327        );
2328
2329        let d1str = format!("{}", d1);
2330        assert_eq!(&d1str, "1.23456789012345678901234567890123456789e-2");
2331        let mut d2 = BigFloat::from_str(&d1str).unwrap();
2332        d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
2333        assert_eq!(d2, d1);
2334
2335        let d1 = BigFloat::parse(
2336            "-123.456789012345678901234567890123456789",
2337            Radix::Dec,
2338            DEFAULT_P,
2339            RoundingMode::None,
2340            &mut cc,
2341        );
2342        let d1str = format!("{}", d1);
2343        assert_eq!(&d1str, "-1.23456789012345678901234567890123456789e+2");
2344        let mut d2 = BigFloat::from_str(&d1str).unwrap();
2345        d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
2346        assert_eq!(d2, d1);
2347
2348        let d1str = format!("{}", INF_POS);
2349        assert_eq!(d1str, "Inf");
2350
2351        let d1str = format!("{}", INF_NEG);
2352        assert_eq!(d1str, "-Inf");
2353
2354        let d1str = format!("{}", NAN);
2355        assert_eq!(d1str, "NaN");
2356
2357        assert!(BigFloat::from_str("abc").is_ok());
2358        assert!(BigFloat::from_str("abc").unwrap().is_nan());
2359    }
2360
2361    #[test]
2362    pub fn test_ops() {
2363        let mut cc = Consts::new().unwrap();
2364
2365        let d1 = -&(TWO.clone());
2366        assert!(d1.is_negative());
2367
2368        let p = DEFAULT_P;
2369        let rm = RoundingMode::ToEven;
2370        assert!(
2371            BigFloat::from_i8(-123, p) == BigFloat::parse("-1.23e+2", Radix::Dec, p, rm, &mut cc)
2372        );
2373        assert!(
2374            BigFloat::from_u8(123, p) == BigFloat::parse("1.23e+2", Radix::Dec, p, rm, &mut cc)
2375        );
2376        assert!(
2377            BigFloat::from_i16(-12312, p)
2378                == BigFloat::parse("-1.2312e+4", Radix::Dec, p, rm, &mut cc)
2379        );
2380        assert!(
2381            BigFloat::from_u16(12312, p)
2382                == BigFloat::parse("1.2312e+4", Radix::Dec, p, rm, &mut cc)
2383        );
2384        assert!(
2385            BigFloat::from_i32(-123456789, p)
2386                == BigFloat::parse("-1.23456789e+8", Radix::Dec, p, rm, &mut cc)
2387        );
2388        assert!(
2389            BigFloat::from_u32(123456789, p)
2390                == BigFloat::parse("1.23456789e+8", Radix::Dec, p, rm, &mut cc)
2391        );
2392        assert!(
2393            BigFloat::from_i64(-1234567890123456789, p)
2394                == BigFloat::parse("-1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
2395        );
2396        assert!(
2397            BigFloat::from_u64(1234567890123456789, p)
2398                == BigFloat::parse("1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
2399        );
2400        assert!(
2401            BigFloat::from_i128(-123456789012345678901234567890123456789, p)
2402                == BigFloat::parse(
2403                    "-1.23456789012345678901234567890123456789e+38",
2404                    Radix::Dec,
2405                    p,
2406                    rm,
2407                    &mut cc
2408                )
2409        );
2410        assert!(
2411            BigFloat::from_u128(123456789012345678901234567890123456789, p)
2412                == BigFloat::parse(
2413                    "1.23456789012345678901234567890123456789e+38",
2414                    Radix::Dec,
2415                    p,
2416                    rm,
2417                    &mut cc
2418                )
2419        );
2420
2421        let neg = BigFloat::from_i8(-3, WORD_BIT_SIZE);
2422        let pos = BigFloat::from_i8(5, WORD_BIT_SIZE);
2423
2424        assert!(pos > neg);
2425        assert!(neg < pos);
2426        assert!(!(pos < neg));
2427        assert!(!(neg > pos));
2428        assert!(INF_NEG < neg);
2429        assert!(INF_NEG < pos);
2430        assert!(INF_NEG < INF_POS);
2431        assert!(!(INF_NEG > neg));
2432        assert!(!(INF_NEG > pos));
2433        assert!(!(INF_NEG > INF_POS));
2434        assert!(INF_POS > neg);
2435        assert!(INF_POS > pos);
2436        assert!(INF_POS > INF_NEG);
2437        assert!(!(INF_POS < neg));
2438        assert!(!(INF_POS < pos));
2439        assert!(!(INF_POS < INF_NEG));
2440        assert!(!(INF_POS > INF_POS));
2441        assert!(!(INF_POS < INF_POS));
2442        assert!(!(INF_NEG > INF_NEG));
2443        assert!(!(INF_NEG < INF_NEG));
2444        assert!(!(INF_POS > NAN));
2445        assert!(!(INF_POS < NAN));
2446        assert!(!(INF_NEG > NAN));
2447        assert!(!(INF_NEG < NAN));
2448        assert!(!(NAN > INF_POS));
2449        assert!(!(NAN < INF_POS));
2450        assert!(!(NAN > INF_NEG));
2451        assert!(!(NAN < INF_NEG));
2452        assert!(!(NAN > NAN));
2453        assert!(!(NAN < NAN));
2454        assert!(!(neg > NAN));
2455        assert!(!(neg < NAN));
2456        assert!(!(pos > NAN));
2457        assert!(!(pos < NAN));
2458        assert!(!(NAN > neg));
2459        assert!(!(NAN < neg));
2460        assert!(!(NAN > pos));
2461        assert!(!(NAN < pos));
2462
2463        assert!(!(NAN == NAN));
2464        assert!(!(NAN == INF_POS));
2465        assert!(!(NAN == INF_NEG));
2466        assert!(!(INF_POS == NAN));
2467        assert!(!(INF_NEG == NAN));
2468        assert!(!(INF_NEG == INF_POS));
2469        assert!(!(INF_POS == INF_NEG));
2470        assert!(!(INF_POS == neg));
2471        assert!(!(INF_POS == pos));
2472        assert!(!(INF_NEG == neg));
2473        assert!(!(INF_NEG == pos));
2474        assert!(!(neg == INF_POS));
2475        assert!(!(pos == INF_POS));
2476        assert!(!(neg == INF_NEG));
2477        assert!(!(pos == INF_NEG));
2478        assert!(!(pos == neg));
2479        assert!(!(neg == pos));
2480        assert!(neg == neg);
2481        assert!(pos == pos);
2482        assert!(INF_NEG == INF_NEG);
2483        assert!(INF_POS == INF_POS);
2484    }
2485}
2486
2487#[cfg(feature = "random")]
2488#[cfg(test)]
2489mod rand_tests {
2490
2491    use super::*;
2492    use crate::defs::EXPONENT_MAX;
2493
2494    #[test]
2495    fn test_rand() {
2496        for _ in 0..1000 {
2497            let p = rand::random::<usize>() % 1000 + DEFAULT_P;
2498            let exp_from;
2499            #[cfg(not(target_pointer_width = "32"))]
2500            {
2501                exp_from = rand::random::<Exponent>().abs();
2502            }
2503            #[cfg(target_pointer_width = "32")]
2504            {
2505                use crate::defs::EXPONENT_MIN;
2506                exp_from =
2507                    rand::random::<Exponent>().abs() % (EXPONENT_MAX - EXPONENT_MIN) + EXPONENT_MIN;
2508            }
2509            let exp_shift = if EXPONENT_MAX > exp_from {
2510                rand::random::<Exponent>().abs()
2511                    % (EXPONENT_MAX as isize - exp_from as isize) as Exponent
2512            } else {
2513                0
2514            };
2515            let exp_to = (exp_from as isize + exp_shift as isize) as Exponent;
2516
2517            let n = BigFloat::random_normal(p, exp_from, exp_to);
2518
2519            assert!(!n.is_subnormal());
2520            assert!(n.exponent().unwrap() >= exp_from && n.exponent().unwrap() <= exp_to);
2521            assert!(n.precision().unwrap() >= p);
2522        }
2523    }
2524}