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    #[test]
1702    fn test_ext() {
1703        let rm = RoundingMode::ToOdd;
1704        let mut cc = Consts::new().unwrap();
1705
1706        // Inf & NaN
1707        let d1 = BigFloat::from_u8(1, rand_p());
1708        assert!(!d1.is_inf());
1709        assert!(!d1.is_nan());
1710        assert!(!d1.is_inf_pos());
1711        assert!(!d1.is_inf_neg());
1712        assert!(d1.is_positive());
1713
1714        let mut d1 = d1.div(&BigFloat::new(rand_p()), rand_p(), rm);
1715        assert!(d1.is_inf());
1716        assert!(!d1.is_nan());
1717        assert!(d1.is_inf_pos());
1718        assert!(!d1.is_inf_neg());
1719        assert!(d1.is_positive());
1720
1721        d1.inv_sign();
1722        assert!(d1.is_inf());
1723        assert!(!d1.is_nan());
1724        assert!(!d1.is_inf_pos());
1725        assert!(d1.is_inf_neg());
1726        assert!(d1.is_negative());
1727
1728        let d1 = BigFloat::new(rand_p()).div(&BigFloat::new(rand_p()), rand_p(), rm);
1729        assert!(!d1.is_inf());
1730        assert!(d1.is_nan());
1731        assert!(!d1.is_inf_pos());
1732        assert!(!d1.is_inf_neg());
1733        assert!(d1.sign().is_none());
1734
1735        for _ in 0..1000 {
1736            let i = rand::random::<i64>();
1737            let d1 = BigFloat::from_i64(i, rand_p());
1738            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1739            assert!(d1.cmp(&n1) == Some(0));
1740
1741            let i = rand::random::<u64>();
1742            let d1 = BigFloat::from_u64(i, rand_p());
1743            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1744            assert!(d1.cmp(&n1) == Some(0));
1745
1746            let i = rand::random::<i128>();
1747            let d1 = BigFloat::from_i128(i, rand_p());
1748            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1749            assert!(d1.cmp(&n1) == Some(0));
1750
1751            let i = rand::random::<u128>();
1752            let d1 = BigFloat::from_u128(i, rand_p());
1753            let n1 = BigFloat::parse(&format!("{}", i), Radix::Dec, rand_p(), rm, &mut cc);
1754            assert!(d1.cmp(&n1) == Some(0));
1755        }
1756
1757        assert!(ONE.exponent().is_some());
1758        assert!(INF_POS.exponent().is_none());
1759        assert!(INF_NEG.exponent().is_none());
1760        assert!(NAN.exponent().is_none());
1761
1762        assert!(ONE.as_raw_parts().is_some());
1763        assert!(INF_POS.as_raw_parts().is_none());
1764        assert!(INF_NEG.as_raw_parts().is_none());
1765        assert!(NAN.as_raw_parts().is_none());
1766
1767        assert!(ONE.add(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
1768        assert!(ONE.add(&INF_POS, rand_p(), rm).is_inf_pos());
1769        assert!(INF_POS.add(&ONE, rand_p(), rm).is_inf_pos());
1770        assert!(ONE.add(&INF_NEG, rand_p(), rm).is_inf_neg());
1771        assert!(INF_NEG.add(&ONE, rand_p(), rm).is_inf_neg());
1772        assert!(INF_POS.add(&INF_POS, rand_p(), rm).is_inf_pos());
1773        assert!(INF_POS.add(&INF_NEG, rand_p(), rm).is_nan());
1774        assert!(INF_NEG.add(&INF_NEG, rand_p(), rm).is_inf_neg());
1775        assert!(INF_NEG.add(&INF_POS, rand_p(), rm).is_nan());
1776
1777        assert!(ONE.add_full_prec(&ONE).cmp(&TWO) == Some(0));
1778        assert!(ONE.add_full_prec(&INF_POS).is_inf_pos());
1779        assert!(INF_POS.add_full_prec(&ONE).is_inf_pos());
1780        assert!(ONE.add_full_prec(&INF_NEG).is_inf_neg());
1781        assert!(INF_NEG.add_full_prec(&ONE).is_inf_neg());
1782        assert!(INF_POS.add_full_prec(&INF_POS).is_inf_pos());
1783        assert!(INF_POS.add_full_prec(&INF_NEG).is_nan());
1784        assert!(INF_NEG.add_full_prec(&INF_NEG).is_inf_neg());
1785        assert!(INF_NEG.add_full_prec(&INF_POS).is_nan());
1786
1787        assert!(ONE.sub_full_prec(&ONE).is_zero());
1788        assert!(ONE.sub_full_prec(&INF_POS).is_inf_neg());
1789        assert!(INF_POS.sub_full_prec(&ONE).is_inf_pos());
1790        assert!(ONE.sub_full_prec(&INF_NEG).is_inf_pos());
1791        assert!(INF_NEG.sub_full_prec(&ONE).is_inf_neg());
1792        assert!(INF_POS.sub_full_prec(&INF_POS).is_nan());
1793        assert!(INF_POS.sub_full_prec(&INF_NEG).is_inf_pos());
1794        assert!(INF_NEG.sub_full_prec(&INF_NEG).is_nan());
1795        assert!(INF_NEG.sub_full_prec(&INF_POS).is_inf_neg());
1796
1797        assert!(ONE.mul_full_prec(&ONE).cmp(&ONE) == Some(0));
1798        assert!(ONE.mul_full_prec(&INF_POS).is_inf_pos());
1799        assert!(INF_POS.mul_full_prec(&ONE).is_inf_pos());
1800        assert!(ONE.mul_full_prec(&INF_NEG).is_inf_neg());
1801        assert!(INF_NEG.mul_full_prec(&ONE).is_inf_neg());
1802        assert!(INF_POS.mul_full_prec(&INF_POS).is_inf_pos());
1803        assert!(INF_POS.mul_full_prec(&INF_NEG).is_inf_neg());
1804        assert!(INF_NEG.mul_full_prec(&INF_NEG).is_inf_pos());
1805        assert!(INF_NEG.mul_full_prec(&INF_POS).is_inf_neg());
1806
1807        assert!(TWO.sub(&ONE, rand_p(), rm).cmp(&ONE) == Some(0));
1808        assert!(ONE.sub(&INF_POS, rand_p(), rm).is_inf_neg());
1809        assert!(INF_POS.sub(&ONE, rand_p(), rm).is_inf_pos());
1810        assert!(ONE.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
1811        assert!(INF_NEG.sub(&ONE, rand_p(), rm).is_inf_neg());
1812        assert!(INF_POS.sub(&INF_POS, rand_p(), rm).is_nan());
1813        assert!(INF_POS.sub(&INF_NEG, rand_p(), rm).is_inf_pos());
1814        assert!(INF_NEG.sub(&INF_NEG, rand_p(), rm).is_nan());
1815        assert!(INF_NEG.sub(&INF_POS, rand_p(), rm).is_inf_neg());
1816
1817        assert!(TWO.mul(&ONE, rand_p(), rm).cmp(&TWO) == Some(0));
1818        assert!(ONE.mul(&INF_POS, rand_p(), rm).is_inf_pos());
1819        assert!(INF_POS.mul(&ONE, rand_p(), rm).is_inf_pos());
1820        assert!(ONE.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
1821        assert!(INF_NEG.mul(&ONE, rand_p(), rm).is_inf_neg());
1822        assert!(ONE.neg().mul(&INF_POS, rand_p(), rm).is_inf_neg());
1823        assert!(ONE.neg().mul(&INF_NEG, rand_p(), rm).is_inf_pos());
1824        assert!(INF_POS.mul(&ONE.neg(), rand_p(), rm).is_inf_neg());
1825        assert!(INF_NEG.mul(&ONE.neg(), rand_p(), rm).is_inf_pos());
1826        assert!(INF_POS.mul(&INF_POS, rand_p(), rm).is_inf_pos());
1827        assert!(INF_POS.mul(&INF_NEG, rand_p(), rm).is_inf_neg());
1828        assert!(INF_NEG.mul(&INF_NEG, rand_p(), rm).is_inf_pos());
1829        assert!(INF_NEG.mul(&INF_POS, rand_p(), rm).is_inf_neg());
1830        assert!(INF_POS.mul(&BigFloat::new(rand_p()), rand_p(), rm).is_nan());
1831        assert!(INF_NEG.mul(&BigFloat::new(rand_p()), rand_p(), rm).is_nan());
1832        assert!(BigFloat::new(rand_p()).mul(&INF_POS, rand_p(), rm).is_nan());
1833        assert!(BigFloat::new(rand_p()).mul(&INF_NEG, rand_p(), rm).is_nan());
1834
1835        assert!(TWO.div(&TWO, rand_p(), rm).cmp(&ONE) == Some(0));
1836        assert!(TWO.div(&INF_POS, rand_p(), rm).is_zero());
1837        assert!(INF_POS.div(&TWO, rand_p(), rm).is_inf_pos());
1838        assert!(TWO.div(&INF_NEG, rand_p(), rm).is_zero());
1839        assert!(INF_NEG.div(&TWO, rand_p(), rm).is_inf_neg());
1840        assert!(TWO.neg().div(&INF_POS, rand_p(), rm).is_zero());
1841        assert!(TWO.neg().div(&INF_NEG, rand_p(), rm).is_zero());
1842        assert!(INF_POS.div(&TWO.neg(), rand_p(), rm).is_inf_neg());
1843        assert!(INF_NEG.div(&TWO.neg(), rand_p(), rm).is_inf_pos());
1844        assert!(INF_POS.div(&INF_POS, rand_p(), rm).is_nan());
1845        assert!(INF_POS.div(&INF_NEG, rand_p(), rm).is_nan());
1846        assert!(INF_NEG.div(&INF_NEG, rand_p(), rm).is_nan());
1847        assert!(INF_NEG.div(&INF_POS, rand_p(), rm).is_nan());
1848        assert!(INF_POS
1849            .div(&BigFloat::new(rand_p()), rand_p(), rm)
1850            .is_inf_pos());
1851        assert!(INF_NEG
1852            .div(&BigFloat::new(rand_p()), rand_p(), rm)
1853            .is_inf_neg());
1854        assert!(BigFloat::new(rand_p())
1855            .div(&INF_POS, rand_p(), rm)
1856            .is_zero());
1857        assert!(BigFloat::new(rand_p())
1858            .div(&INF_NEG, rand_p(), rm)
1859            .is_zero());
1860
1861        assert!(TWO.rem(&TWO).is_zero());
1862        assert!(TWO.rem(&INF_POS).cmp(&TWO) == Some(0));
1863        assert!(INF_POS.rem(&TWO).is_nan());
1864        assert!(TWO.rem(&INF_NEG).cmp(&TWO) == Some(0));
1865        assert!(INF_NEG.rem(&TWO).is_nan());
1866        assert!(TWO.neg().rem(&INF_POS).cmp(&TWO.neg()) == Some(0));
1867        assert!(TWO.neg().rem(&INF_NEG).cmp(&TWO.neg()) == Some(0));
1868        assert!(INF_POS.rem(&TWO.neg()).is_nan());
1869        assert!(INF_NEG.rem(&TWO.neg()).is_nan());
1870        assert!(INF_POS.rem(&INF_POS).is_nan());
1871        assert!(INF_POS.rem(&INF_NEG).is_nan());
1872        assert!(INF_NEG.rem(&INF_NEG).is_nan());
1873        assert!(INF_NEG.rem(&INF_POS).is_nan());
1874        assert!(INF_POS.rem(&BigFloat::new(rand_p())).is_nan());
1875        assert!(INF_NEG.rem(&BigFloat::new(rand_p())).is_nan());
1876        assert!(BigFloat::new(rand_p()).rem(&INF_POS).is_zero());
1877        assert!(BigFloat::new(rand_p()).rem(&INF_NEG).is_zero());
1878
1879        for op in [BigFloat::add, BigFloat::sub, BigFloat::mul, BigFloat::div] {
1880            assert!(op(&NAN, &ONE, rand_p(), rm).is_nan());
1881            assert!(op(&ONE, &NAN, rand_p(), rm).is_nan());
1882            assert!(op(&NAN, &INF_POS, rand_p(), rm).is_nan());
1883            assert!(op(&INF_POS, &NAN, rand_p(), rm).is_nan());
1884            assert!(op(&NAN, &INF_NEG, rand_p(), rm).is_nan());
1885            assert!(op(&INF_NEG, &NAN, rand_p(), rm).is_nan());
1886            assert!(op(&NAN, &NAN, rand_p(), rm).is_nan());
1887        }
1888
1889        assert!(BigFloat::rem(&NAN, &ONE).is_nan());
1890        assert!(BigFloat::rem(&ONE, &NAN).is_nan());
1891        assert!(BigFloat::rem(&NAN, &INF_POS).is_nan());
1892        assert!(BigFloat::rem(&INF_POS, &NAN).is_nan());
1893        assert!(BigFloat::rem(&NAN, &INF_NEG).is_nan());
1894        assert!(BigFloat::rem(&INF_NEG, &NAN).is_nan());
1895        assert!(BigFloat::rem(&NAN, &NAN).is_nan());
1896
1897        for op in [BigFloat::add_full_prec, BigFloat::sub_full_prec, BigFloat::mul_full_prec] {
1898            assert!(op(&NAN, &ONE).is_nan());
1899            assert!(op(&ONE, &NAN).is_nan());
1900            assert!(op(&NAN, &INF_POS).is_nan());
1901            assert!(op(&INF_POS, &NAN).is_nan());
1902            assert!(op(&NAN, &INF_NEG).is_nan());
1903            assert!(op(&INF_NEG, &NAN).is_nan());
1904            assert!(op(&NAN, &NAN).is_nan());
1905        }
1906
1907        assert!(ONE.cmp(&ONE).unwrap() == 0);
1908        assert!(ONE.cmp(&INF_POS).unwrap() < 0);
1909        assert!(INF_POS.cmp(&ONE).unwrap() > 0);
1910        assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
1911        assert!(ONE.cmp(&INF_NEG).unwrap() > 0);
1912        assert!(INF_NEG.cmp(&ONE).unwrap() < 0);
1913        assert!(INF_NEG.cmp(&INF_NEG).unwrap() == 0);
1914        assert!(INF_POS.cmp(&INF_NEG).unwrap() > 0);
1915        assert!(INF_NEG.cmp(&INF_POS).unwrap() < 0);
1916        assert!(INF_POS.cmp(&INF_POS).unwrap() == 0);
1917        assert!(ONE.cmp(&NAN).is_none());
1918        assert!(NAN.cmp(&ONE).is_none());
1919        assert!(INF_POS.cmp(&NAN).is_none());
1920        assert!(NAN.cmp(&INF_POS).is_none());
1921        assert!(INF_NEG.cmp(&NAN).is_none());
1922        assert!(NAN.cmp(&INF_NEG).is_none());
1923        assert!(NAN.cmp(&NAN).is_none());
1924
1925        assert!(ONE.abs_cmp(&ONE).unwrap() == 0);
1926        assert!(ONE.abs_cmp(&INF_POS).unwrap() < 0);
1927        assert!(INF_POS.abs_cmp(&ONE).unwrap() > 0);
1928        assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
1929        assert!(ONE.abs_cmp(&INF_NEG).unwrap() < 0);
1930        assert!(INF_NEG.abs_cmp(&ONE).unwrap() > 0);
1931        assert!(INF_NEG.abs_cmp(&INF_NEG).unwrap() == 0);
1932        assert!(INF_POS.abs_cmp(&INF_NEG).unwrap() == 0);
1933        assert!(INF_NEG.abs_cmp(&INF_POS).unwrap() == 0);
1934        assert!(INF_POS.abs_cmp(&INF_POS).unwrap() == 0);
1935        assert!(ONE.abs_cmp(&NAN).is_none());
1936        assert!(NAN.abs_cmp(&ONE).is_none());
1937        assert!(INF_POS.abs_cmp(&NAN).is_none());
1938        assert!(NAN.abs_cmp(&INF_POS).is_none());
1939        assert!(INF_NEG.abs_cmp(&NAN).is_none());
1940        assert!(NAN.abs_cmp(&INF_NEG).is_none());
1941        assert!(NAN.abs_cmp(&NAN).is_none());
1942
1943        assert!(ONE.is_positive());
1944        assert!(!ONE.is_negative());
1945
1946        assert!(ONE.neg().is_negative());
1947        assert!(!ONE.neg().is_positive());
1948        assert!(!INF_POS.is_negative());
1949        assert!(INF_POS.is_positive());
1950        assert!(INF_NEG.is_negative());
1951        assert!(!INF_NEG.is_positive());
1952        assert!(!NAN.is_positive());
1953        assert!(!NAN.is_negative());
1954
1955        assert!(ONE.pow(&ONE, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1956        assert!(BigFloat::new(DEFAULT_P)
1957            .pow(&INF_POS, rand_p(), rm, &mut cc)
1958            .is_zero());
1959        assert!(BigFloat::new(DEFAULT_P)
1960            .pow(&INF_NEG, rand_p(), rm, &mut cc)
1961            .is_zero());
1962        assert!(ONE.pow(&INF_POS, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1963        assert!(ONE.pow(&INF_NEG, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1964        assert!(TWO.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
1965        assert!(TWO.pow(&INF_NEG, rand_p(), rm, &mut cc).is_inf_neg());
1966        assert!(INF_POS.pow(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
1967        assert!(INF_NEG.pow(&ONE, rand_p(), rm, &mut cc).is_inf_neg());
1968        assert!(INF_NEG.pow(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
1969        assert!(INF_NEG
1970            .pow(&BigFloat::from_f64(10.2, DEFAULT_P), rand_p(), rm, &mut cc)
1971            .is_inf_pos());
1972        assert!(INF_NEG
1973            .pow(&BigFloat::from_f64(3.0, DEFAULT_P), rand_p(), rm, &mut cc)
1974            .is_inf_neg());
1975        assert!(INF_POS.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
1976        assert!(INF_NEG.pow(&ONE.neg(), rand_p(), rm, &mut cc).is_zero());
1977        assert!(
1978            INF_POS
1979                .pow(&BigFloat::new(DEFAULT_P), rand_p(), rm, &mut cc)
1980                .cmp(&ONE)
1981                == Some(0)
1982        );
1983        assert!(
1984            INF_NEG
1985                .pow(&BigFloat::new(DEFAULT_P), rand_p(), rm, &mut cc)
1986                .cmp(&ONE)
1987                == Some(0)
1988        );
1989        assert!(INF_POS.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
1990        assert!(INF_NEG.pow(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
1991        assert!(INF_POS.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
1992        assert!(INF_NEG.pow(&INF_NEG, rand_p(), rm, &mut cc).is_zero());
1993
1994        let half = ONE.div(&TWO, rand_p(), rm);
1995        assert!(TWO.log(&TWO, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
1996        assert!(TWO.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
1997        assert!(TWO.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
1998        assert!(INF_POS.log(&TWO, rand_p(), rm, &mut cc).is_inf_pos());
1999        assert!(INF_NEG.log(&TWO, rand_p(), rm, &mut cc).is_nan());
2000        assert!(half.log(&half, rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
2001        assert!(half.log(&INF_POS, rand_p(), rm, &mut cc).is_zero());
2002        assert!(half.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2003        assert!(INF_POS.log(&half, rand_p(), rm, &mut cc).is_inf_neg());
2004        assert!(INF_NEG.log(&half, rand_p(), rm, &mut cc).is_nan());
2005        assert!(INF_POS.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2006        assert!(INF_POS.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2007        assert!(INF_NEG.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2008        assert!(INF_NEG.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2009        assert!(TWO.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
2010        assert!(half.log(&ONE, rand_p(), rm, &mut cc).is_inf_pos());
2011        assert!(ONE.log(&ONE, rand_p(), rm, &mut cc).is_nan());
2012
2013        assert!(BigFloat::from_f32(f32::NAN, DEFAULT_P).is_nan());
2014        assert!(BigFloat::from_f32(f32::INFINITY, DEFAULT_P).is_inf_pos());
2015        assert!(BigFloat::from_f32(f32::NEG_INFINITY, DEFAULT_P).is_inf_neg());
2016        assert!(!BigFloat::from_f32(1.0, DEFAULT_P).is_nan());
2017        assert!(BigFloat::from_f64(f64::NAN, DEFAULT_P).is_nan());
2018        assert!(BigFloat::from_f64(f64::INFINITY, DEFAULT_P).is_inf_pos());
2019        assert!(BigFloat::from_f64(f64::NEG_INFINITY, DEFAULT_P).is_inf_neg());
2020        assert!(!BigFloat::from_f64(1.0, DEFAULT_P).is_nan());
2021
2022        assert!(ONE.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2023        assert!(NAN.pow(&ONE, rand_p(), rm, &mut cc).is_nan());
2024        assert!(INF_POS.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2025        assert!(NAN.pow(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2026        assert!(INF_NEG.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2027        assert!(NAN.pow(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2028        assert!(NAN.pow(&NAN, rand_p(), rm, &mut cc).is_nan());
2029
2030        assert!(NAN.powi(2, rand_p(), rm).is_nan());
2031        assert!(NAN.powi(0, rand_p(), rm).is_nan());
2032        assert!(INF_POS.powi(2, rand_p(), rm).is_inf_pos());
2033        assert!(INF_POS.powi(3, rand_p(), rm).is_inf_pos());
2034        assert!(INF_NEG.powi(4, rand_p(), rm).is_inf_pos());
2035        assert!(INF_NEG.powi(5, rand_p(), rm).is_inf_neg());
2036        assert!(INF_POS.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
2037        assert!(INF_NEG.powi(0, rand_p(), rm).cmp(&ONE) == Some(0));
2038
2039        assert!(TWO.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2040        assert!(NAN.log(&TWO, rand_p(), rm, &mut cc).is_nan());
2041        assert!(INF_POS.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2042        assert!(NAN.log(&INF_POS, rand_p(), rm, &mut cc).is_nan());
2043        assert!(INF_NEG.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2044        assert!(NAN.log(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2045        assert!(NAN.log(&NAN, rand_p(), rm, &mut cc).is_nan());
2046
2047        assert!(INF_NEG.abs().is_inf_pos());
2048        assert!(INF_POS.abs().is_inf_pos());
2049        assert!(NAN.abs().is_nan());
2050
2051        assert!(INF_NEG.int().is_nan());
2052        assert!(INF_POS.int().is_nan());
2053        assert!(NAN.int().is_nan());
2054
2055        assert!(INF_NEG.fract().is_nan());
2056        assert!(INF_POS.fract().is_nan());
2057        assert!(NAN.fract().is_nan());
2058
2059        assert!(INF_NEG.ceil().is_inf_neg());
2060        assert!(INF_POS.ceil().is_inf_pos());
2061        assert!(NAN.ceil().is_nan());
2062
2063        assert!(INF_NEG.floor().is_inf_neg());
2064        assert!(INF_POS.floor().is_inf_pos());
2065        assert!(NAN.floor().is_nan());
2066
2067        for rm in [
2068            RoundingMode::Up,
2069            RoundingMode::Down,
2070            RoundingMode::ToZero,
2071            RoundingMode::FromZero,
2072            RoundingMode::ToEven,
2073            RoundingMode::ToOdd,
2074        ] {
2075            assert!(INF_NEG.round(0, rm).is_inf_neg());
2076            assert!(INF_POS.round(0, rm).is_inf_pos());
2077            assert!(NAN.round(0, rm).is_nan());
2078        }
2079
2080        assert!(INF_NEG.sqrt(rand_p(), rm).is_nan());
2081        assert!(INF_POS.sqrt(rand_p(), rm).is_inf_pos());
2082        assert!(NAN.sqrt(rand_p(), rm).is_nan());
2083
2084        assert!(INF_NEG.cbrt(rand_p(), rm).is_inf_neg());
2085        assert!(INF_POS.cbrt(rand_p(), rm).is_inf_pos());
2086        assert!(NAN.cbrt(rand_p(), rm).is_nan());
2087
2088        for op in [BigFloat::ln, BigFloat::log2, BigFloat::log10] {
2089            assert!(op(&INF_NEG, rand_p(), rm, &mut cc).is_nan());
2090            assert!(op(&INF_POS, rand_p(), rm, &mut cc).is_inf_pos());
2091            assert!(op(&NAN, rand_p(), rm, &mut cc).is_nan());
2092        }
2093
2094        assert!(INF_NEG.exp(rand_p(), rm, &mut cc).is_zero());
2095        assert!(INF_POS.exp(rand_p(), rm, &mut cc).is_inf_pos());
2096        assert!(NAN.exp(rand_p(), rm, &mut cc).is_nan());
2097
2098        assert!(INF_NEG.sin(rand_p(), rm, &mut cc).is_nan());
2099        assert!(INF_POS.sin(rand_p(), rm, &mut cc).is_nan());
2100        assert!(NAN.sin(rand_p(), rm, &mut cc).is_nan());
2101
2102        assert!(INF_NEG.cos(rand_p(), rm, &mut cc).is_nan());
2103        assert!(INF_POS.cos(rand_p(), rm, &mut cc).is_nan());
2104        assert!(NAN.cos(rand_p(), rm, &mut cc).is_nan());
2105
2106        assert!(INF_NEG.tan(rand_p(), rm, &mut cc).is_nan());
2107        assert!(INF_POS.tan(rand_p(), rm, &mut cc).is_nan());
2108        assert!(NAN.tan(rand_p(), rm, &mut cc).is_nan());
2109
2110        assert!(INF_NEG.asin(rand_p(), rm, &mut cc).is_nan());
2111        assert!(INF_POS.asin(rand_p(), rm, &mut cc).is_nan());
2112        assert!(NAN.asin(rand_p(), rm, &mut cc).is_nan());
2113
2114        assert!(INF_NEG.acos(rand_p(), rm, &mut cc).is_nan());
2115        assert!(INF_POS.acos(rand_p(), rm, &mut cc).is_nan());
2116        assert!(NAN.acos(rand_p(), rm, &mut cc).is_nan());
2117
2118        let p = rand_p();
2119        let mut half_pi: BigFloat = cc.pi_num(p, rm).unwrap().into();
2120        half_pi.set_exponent(1);
2121        assert!(INF_NEG.atan(p, rm, &mut cc).cmp(&half_pi.neg()) == Some(0));
2122        assert!(INF_POS.atan(p, rm, &mut cc).cmp(&half_pi) == Some(0));
2123        assert!(NAN.atan(rand_p(), rm, &mut cc).is_nan());
2124
2125        assert!(INF_NEG.sinh(rand_p(), rm, &mut cc).is_inf_neg());
2126        assert!(INF_POS.sinh(rand_p(), rm, &mut cc).is_inf_pos());
2127        assert!(NAN.sinh(rand_p(), rm, &mut cc).is_nan());
2128
2129        assert!(INF_NEG.cosh(rand_p(), rm, &mut cc).is_inf_pos());
2130        assert!(INF_POS.cosh(rand_p(), rm, &mut cc).is_inf_pos());
2131        assert!(NAN.cosh(rand_p(), rm, &mut cc).is_nan());
2132
2133        assert!(INF_NEG.tanh(rand_p(), rm, &mut cc).cmp(&ONE.neg()) == Some(0));
2134        assert!(INF_POS.tanh(rand_p(), rm, &mut cc).cmp(&ONE) == Some(0));
2135        assert!(NAN.tanh(rand_p(), rm, &mut cc).is_nan());
2136
2137        assert!(INF_NEG.asinh(rand_p(), rm, &mut cc).is_inf_neg());
2138        assert!(INF_POS.asinh(rand_p(), rm, &mut cc).is_inf_pos());
2139        assert!(NAN.asinh(rand_p(), rm, &mut cc).is_nan());
2140
2141        assert!(INF_NEG.acosh(rand_p(), rm, &mut cc).is_nan());
2142        assert!(INF_POS.acosh(rand_p(), rm, &mut cc).is_inf_pos());
2143        assert!(NAN.acosh(rand_p(), rm, &mut cc).is_nan());
2144
2145        assert!(INF_NEG.atanh(rand_p(), rm, &mut cc).is_nan());
2146        assert!(INF_POS.atanh(rand_p(), rm, &mut cc).is_nan());
2147        assert!(NAN.atanh(rand_p(), rm, &mut cc).is_nan());
2148
2149        assert!(INF_NEG.reciprocal(rand_p(), rm).is_zero());
2150        assert!(INF_POS.reciprocal(rand_p(), rm).is_zero());
2151        assert!(NAN.reciprocal(rand_p(), rm).is_nan());
2152
2153        assert!(TWO.signum().cmp(&ONE) == Some(0));
2154        assert!(TWO.neg().signum().cmp(&ONE.neg()) == Some(0));
2155        assert!(INF_POS.signum().cmp(&ONE) == Some(0));
2156        assert!(INF_NEG.signum().cmp(&ONE.neg()) == Some(0));
2157        assert!(NAN.signum().is_nan());
2158
2159        let d1 = ONE.clone();
2160        assert!(d1.exponent() == Some(1));
2161        let words: &[Word] = {
2162            #[cfg(not(target_arch = "x86"))]
2163            {
2164                &[0, 0x8000000000000000]
2165            }
2166            #[cfg(target_arch = "x86")]
2167            {
2168                &[0, 0, 0, 0x80000000]
2169            }
2170        };
2171
2172        assert!(d1.mantissa_digits() == Some(words));
2173        assert!(d1.mantissa_max_bit_len() == Some(DEFAULT_P));
2174        assert!(d1.precision() == Some(DEFAULT_P));
2175        assert!(d1.sign() == Some(Sign::Pos));
2176
2177        assert!(INF_POS.exponent().is_none());
2178        assert!(INF_POS.mantissa_digits().is_none());
2179        assert!(INF_POS.mantissa_max_bit_len().is_none());
2180        assert!(INF_POS.precision().is_none());
2181        assert!(INF_POS.sign() == Some(Sign::Pos));
2182
2183        assert!(INF_NEG.exponent().is_none());
2184        assert!(INF_NEG.mantissa_digits().is_none());
2185        assert!(INF_NEG.mantissa_max_bit_len().is_none());
2186        assert!(INF_NEG.precision().is_none());
2187        assert!(INF_NEG.sign() == Some(Sign::Neg));
2188
2189        assert!(NAN.exponent().is_none());
2190        assert!(NAN.mantissa_digits().is_none());
2191        assert!(NAN.mantissa_max_bit_len().is_none());
2192        assert!(NAN.precision().is_none());
2193        assert!(NAN.sign().is_none());
2194
2195        INF_POS.clone().set_exponent(1);
2196        INF_POS.clone().set_precision(1, rm).unwrap();
2197        INF_POS.clone().set_sign(Sign::Pos);
2198
2199        INF_NEG.clone().set_exponent(1);
2200        INF_NEG.clone().set_precision(1, rm).unwrap();
2201        INF_NEG.clone().set_sign(Sign::Pos);
2202
2203        NAN.clone().set_exponent(1);
2204        NAN.clone().set_precision(1, rm).unwrap();
2205        NAN.clone().set_sign(Sign::Pos);
2206
2207        assert!(INF_POS.min(&ONE).cmp(&ONE) == Some(0));
2208        assert!(INF_NEG.min(&ONE).is_inf_neg());
2209        assert!(NAN.min(&ONE).is_nan());
2210        assert!(ONE.min(&INF_POS).cmp(&ONE) == Some(0));
2211        assert!(ONE.min(&INF_NEG).is_inf_neg());
2212        assert!(ONE.min(&NAN).is_nan());
2213        assert!(NAN.min(&INF_POS).is_nan());
2214        assert!(NAN.min(&INF_NEG).is_nan());
2215        assert!(NAN.min(&NAN).is_nan());
2216        assert!(INF_NEG.min(&INF_POS).is_inf_neg());
2217        assert!(INF_POS.min(&INF_NEG).is_inf_neg());
2218        assert!(INF_POS.min(&INF_POS).is_inf_pos());
2219        assert!(INF_NEG.min(&INF_NEG).is_inf_neg());
2220
2221        assert!(INF_POS.max(&ONE).is_inf_pos());
2222        assert!(INF_NEG.max(&ONE).cmp(&ONE) == Some(0));
2223        assert!(NAN.max(&ONE).is_nan());
2224        assert!(ONE.max(&INF_POS).is_inf_pos());
2225        assert!(ONE.max(&INF_NEG).cmp(&ONE) == Some(0));
2226        assert!(ONE.max(&NAN).is_nan());
2227        assert!(NAN.max(&INF_POS).is_nan());
2228        assert!(NAN.max(&INF_NEG).is_nan());
2229        assert!(NAN.max(&NAN).is_nan());
2230        assert!(INF_NEG.max(&INF_POS).is_inf_pos());
2231        assert!(INF_POS.max(&INF_NEG).is_inf_pos());
2232        assert!(INF_POS.max(&INF_POS).is_inf_pos());
2233        assert!(INF_NEG.max(&INF_NEG).is_inf_neg());
2234
2235        assert!(ONE.clamp(&ONE.neg(), &TWO).cmp(&ONE) == Some(0));
2236        assert!(ONE.clamp(&TWO, &ONE).is_nan());
2237        assert!(ONE.clamp(&INF_POS, &ONE).is_nan());
2238        assert!(ONE.clamp(&TWO, &INF_NEG).is_nan());
2239        assert!(ONE.neg().clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
2240        assert!(TWO.clamp(&ONE.neg(), &ONE).cmp(&ONE) == Some(0));
2241        assert!(INF_POS.clamp(&ONE, &TWO).cmp(&TWO) == Some(0));
2242        assert!(INF_POS.clamp(&ONE, &INF_POS).is_inf_pos());
2243        assert!(INF_POS.clamp(&INF_NEG, &ONE).cmp(&ONE) == Some(0));
2244        assert!(INF_POS.clamp(&NAN, &INF_POS).is_nan());
2245        assert!(INF_POS.clamp(&ONE, &NAN).is_nan());
2246        assert!(INF_POS.clamp(&NAN, &NAN).is_nan());
2247        assert!(INF_NEG.clamp(&ONE, &TWO).cmp(&ONE) == Some(0));
2248        assert!(INF_NEG.clamp(&ONE, &INF_POS).cmp(&ONE) == Some(0));
2249        assert!(INF_NEG.clamp(&INF_NEG, &ONE).is_inf_neg());
2250        assert!(INF_NEG.clamp(&NAN, &INF_POS).is_nan());
2251        assert!(INF_NEG.clamp(&ONE, &NAN).is_nan());
2252        assert!(INF_NEG.clamp(&NAN, &NAN).is_nan());
2253        assert!(NAN.clamp(&ONE, &TWO).is_nan());
2254        assert!(NAN.clamp(&NAN, &TWO).is_nan());
2255        assert!(NAN.clamp(&ONE, &NAN).is_nan());
2256        assert!(NAN.clamp(&NAN, &NAN).is_nan());
2257        assert!(NAN.clamp(&INF_NEG, &INF_POS).is_nan());
2258
2259        assert!(BigFloat::min_positive(DEFAULT_P).classify() == FpCategory::Subnormal);
2260        assert!(INF_POS.classify() == FpCategory::Infinite);
2261        assert!(INF_NEG.classify() == FpCategory::Infinite);
2262        assert!(NAN.classify() == FpCategory::Nan);
2263        assert!(ONE.classify() == FpCategory::Normal);
2264
2265        assert!(!INF_POS.is_subnormal());
2266        assert!(!INF_NEG.is_subnormal());
2267        assert!(!NAN.is_subnormal());
2268        assert!(BigFloat::min_positive(DEFAULT_P).is_subnormal());
2269        assert!(!BigFloat::min_positive_normal(DEFAULT_P).is_subnormal());
2270        assert!(!BigFloat::max_value(DEFAULT_P).is_subnormal());
2271        assert!(!BigFloat::min_value(DEFAULT_P).is_subnormal());
2272
2273        let n1 = BigFloat::convert_from_radix(
2274            Sign::Pos,
2275            &[],
2276            0,
2277            Radix::Dec,
2278            usize::MAX - 1,
2279            RoundingMode::None,
2280            &mut cc,
2281        );
2282        assert!(n1.is_nan());
2283        assert!(n1.err() == Some(Error::InvalidArgument));
2284
2285        assert!(
2286            n1.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
2287                == Err(Error::InvalidArgument)
2288        );
2289        assert!(
2290            INF_POS.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
2291                == Err(Error::InvalidArgument)
2292        );
2293        assert!(
2294            INF_NEG.convert_to_radix(Radix::Dec, RoundingMode::None, &mut cc)
2295                == Err(Error::InvalidArgument)
2296        );
2297    }
2298
2299    #[cfg(feature = "std")]
2300    #[test]
2301    fn test_ops_std() {
2302        let mut cc = Consts::new().unwrap();
2303
2304        let d1 = BigFloat::parse(
2305            "0.0123456789012345678901234567890123456789",
2306            Radix::Dec,
2307            DEFAULT_P,
2308            RoundingMode::None,
2309            &mut cc,
2310        );
2311
2312        let d1str = format!("{}", d1);
2313        assert_eq!(&d1str, "1.23456789012345678901234567890123456789e-2");
2314        let mut d2 = BigFloat::from_str(&d1str).unwrap();
2315        d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
2316        assert_eq!(d2, d1);
2317
2318        let d1 = BigFloat::parse(
2319            "-123.456789012345678901234567890123456789",
2320            Radix::Dec,
2321            DEFAULT_P,
2322            RoundingMode::None,
2323            &mut cc,
2324        );
2325        let d1str = format!("{}", d1);
2326        assert_eq!(&d1str, "-1.23456789012345678901234567890123456789e+2");
2327        let mut d2 = BigFloat::from_str(&d1str).unwrap();
2328        d2.set_precision(DEFAULT_P, RoundingMode::ToEven).unwrap();
2329        assert_eq!(d2, d1);
2330
2331        let d1str = format!("{}", INF_POS);
2332        assert_eq!(d1str, "Inf");
2333
2334        let d1str = format!("{}", INF_NEG);
2335        assert_eq!(d1str, "-Inf");
2336
2337        let d1str = format!("{}", NAN);
2338        assert_eq!(d1str, "NaN");
2339
2340        assert!(BigFloat::from_str("abc").is_ok());
2341        assert!(BigFloat::from_str("abc").unwrap().is_nan());
2342    }
2343
2344    #[test]
2345    pub fn test_ops() {
2346        let mut cc = Consts::new().unwrap();
2347
2348        let d1 = -&(TWO.clone());
2349        assert!(d1.is_negative());
2350
2351        let p = DEFAULT_P;
2352        let rm = RoundingMode::ToEven;
2353        assert!(
2354            BigFloat::from_i8(-123, p) == BigFloat::parse("-1.23e+2", Radix::Dec, p, rm, &mut cc)
2355        );
2356        assert!(
2357            BigFloat::from_u8(123, p) == BigFloat::parse("1.23e+2", Radix::Dec, p, rm, &mut cc)
2358        );
2359        assert!(
2360            BigFloat::from_i16(-12312, p)
2361                == BigFloat::parse("-1.2312e+4", Radix::Dec, p, rm, &mut cc)
2362        );
2363        assert!(
2364            BigFloat::from_u16(12312, p)
2365                == BigFloat::parse("1.2312e+4", Radix::Dec, p, rm, &mut cc)
2366        );
2367        assert!(
2368            BigFloat::from_i32(-123456789, p)
2369                == BigFloat::parse("-1.23456789e+8", Radix::Dec, p, rm, &mut cc)
2370        );
2371        assert!(
2372            BigFloat::from_u32(123456789, p)
2373                == BigFloat::parse("1.23456789e+8", Radix::Dec, p, rm, &mut cc)
2374        );
2375        assert!(
2376            BigFloat::from_i64(-1234567890123456789, p)
2377                == BigFloat::parse("-1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
2378        );
2379        assert!(
2380            BigFloat::from_u64(1234567890123456789, p)
2381                == BigFloat::parse("1.234567890123456789e+18", Radix::Dec, p, rm, &mut cc)
2382        );
2383        assert!(
2384            BigFloat::from_i128(-123456789012345678901234567890123456789, p)
2385                == BigFloat::parse(
2386                    "-1.23456789012345678901234567890123456789e+38",
2387                    Radix::Dec,
2388                    p,
2389                    rm,
2390                    &mut cc
2391                )
2392        );
2393        assert!(
2394            BigFloat::from_u128(123456789012345678901234567890123456789, p)
2395                == BigFloat::parse(
2396                    "1.23456789012345678901234567890123456789e+38",
2397                    Radix::Dec,
2398                    p,
2399                    rm,
2400                    &mut cc
2401                )
2402        );
2403
2404        let neg = BigFloat::from_i8(-3, WORD_BIT_SIZE);
2405        let pos = BigFloat::from_i8(5, WORD_BIT_SIZE);
2406
2407        assert!(pos > neg);
2408        assert!(neg < pos);
2409        assert!(!(pos < neg));
2410        assert!(!(neg > pos));
2411        assert!(INF_NEG < neg);
2412        assert!(INF_NEG < pos);
2413        assert!(INF_NEG < INF_POS);
2414        assert!(!(INF_NEG > neg));
2415        assert!(!(INF_NEG > pos));
2416        assert!(!(INF_NEG > INF_POS));
2417        assert!(INF_POS > neg);
2418        assert!(INF_POS > pos);
2419        assert!(INF_POS > INF_NEG);
2420        assert!(!(INF_POS < neg));
2421        assert!(!(INF_POS < pos));
2422        assert!(!(INF_POS < INF_NEG));
2423        assert!(!(INF_POS > INF_POS));
2424        assert!(!(INF_POS < INF_POS));
2425        assert!(!(INF_NEG > INF_NEG));
2426        assert!(!(INF_NEG < INF_NEG));
2427        assert!(!(INF_POS > NAN));
2428        assert!(!(INF_POS < NAN));
2429        assert!(!(INF_NEG > NAN));
2430        assert!(!(INF_NEG < NAN));
2431        assert!(!(NAN > INF_POS));
2432        assert!(!(NAN < INF_POS));
2433        assert!(!(NAN > INF_NEG));
2434        assert!(!(NAN < INF_NEG));
2435        assert!(!(NAN > NAN));
2436        assert!(!(NAN < NAN));
2437        assert!(!(neg > NAN));
2438        assert!(!(neg < NAN));
2439        assert!(!(pos > NAN));
2440        assert!(!(pos < NAN));
2441        assert!(!(NAN > neg));
2442        assert!(!(NAN < neg));
2443        assert!(!(NAN > pos));
2444        assert!(!(NAN < pos));
2445
2446        assert!(!(NAN == NAN));
2447        assert!(!(NAN == INF_POS));
2448        assert!(!(NAN == INF_NEG));
2449        assert!(!(INF_POS == NAN));
2450        assert!(!(INF_NEG == NAN));
2451        assert!(!(INF_NEG == INF_POS));
2452        assert!(!(INF_POS == INF_NEG));
2453        assert!(!(INF_POS == neg));
2454        assert!(!(INF_POS == pos));
2455        assert!(!(INF_NEG == neg));
2456        assert!(!(INF_NEG == pos));
2457        assert!(!(neg == INF_POS));
2458        assert!(!(pos == INF_POS));
2459        assert!(!(neg == INF_NEG));
2460        assert!(!(pos == INF_NEG));
2461        assert!(!(pos == neg));
2462        assert!(!(neg == pos));
2463        assert!(neg == neg);
2464        assert!(pos == pos);
2465        assert!(INF_NEG == INF_NEG);
2466        assert!(INF_POS == INF_POS);
2467    }
2468}
2469
2470#[cfg(feature = "random")]
2471#[cfg(test)]
2472mod rand_tests {
2473
2474    use super::*;
2475    use crate::defs::EXPONENT_MAX;
2476
2477    #[test]
2478    fn test_rand() {
2479        for _ in 0..1000 {
2480            let p = rand::random::<usize>() % 1000 + DEFAULT_P;
2481            let exp_from;
2482            #[cfg(not(target_arch = "x86"))]
2483            {
2484                exp_from = rand::random::<Exponent>().abs();
2485            }
2486            #[cfg(target_arch = "x86")]
2487            {
2488                use crate::defs::EXPONENT_MIN;
2489                exp_from =
2490                    rand::random::<Exponent>().abs() % (EXPONENT_MAX - EXPONENT_MIN) + EXPONENT_MIN;
2491            }
2492            let exp_shift = if EXPONENT_MAX > exp_from {
2493                rand::random::<Exponent>().abs()
2494                    % (EXPONENT_MAX as isize - exp_from as isize) as Exponent
2495            } else {
2496                0
2497            };
2498            let exp_to = (exp_from as isize + exp_shift as isize) as Exponent;
2499
2500            let n = BigFloat::random_normal(p, exp_from, exp_to);
2501
2502            assert!(!n.is_subnormal());
2503            assert!(n.exponent().unwrap() >= exp_from && n.exponent().unwrap() <= exp_to);
2504            assert!(n.precision().unwrap() >= p);
2505        }
2506    }
2507}