Skip to main content

dashu_float/
sign.rs

1use crate::{
2    fbig::FBig,
3    repr::{Context, Repr, Word},
4    round::Round,
5};
6use core::ops::{Mul, MulAssign, Neg};
7use dashu_base::{Abs, Sign, Signed};
8use dashu_int::IBig;
9
10impl<R: Round, const B: Word> FBig<R, B> {
11    /// Get the sign of the number. Positive zero has a positive sign, negative zero has a
12    /// negative sign.
13    ///
14    /// # Examples
15    ///
16    /// ```
17    /// # use core::str::FromStr;
18    /// # use dashu_base::{ParseError, Sign};
19    /// # use dashu_float::DBig;
20    /// assert_eq!(DBig::ZERO.sign(), Sign::Positive);
21    /// assert_eq!(DBig::from_str("-1.234")?.sign(), Sign::Negative);
22    /// # Ok::<(), ParseError>(())
23    /// ```
24    #[inline]
25    pub const fn sign(&self) -> Sign {
26        self.repr.sign()
27    }
28
29    /// A number representing the sign of `self`.
30    ///
31    /// * [FBig::ONE] if the number is positive (including `inf`)
32    /// * [FBig::ZERO] if the number is zero
33    /// * [FBig::NEG_ONE] if the number is negative (including `-inf`)
34    ///
35    /// # Examples
36    /// ```
37    /// # use core::str::FromStr;
38    /// # use dashu_base::ParseError;
39    /// # use dashu_float::DBig;
40    /// assert_eq!(DBig::from_str("2.01")?.signum(), DBig::ONE);
41    /// assert_eq!(DBig::from_str("-1.234")?.signum(), DBig::NEG_ONE);
42    /// # Ok::<(), ParseError>(())
43    /// ```
44    pub const fn signum(&self) -> Self {
45        let significand = if self.repr.significand.is_zero() {
46            // distinguish infinities from signed zero; signum(±0) = +0
47            match self.repr.exponent {
48                isize::MAX => IBig::ONE,
49                isize::MIN => IBig::NEG_ONE,
50                _ => IBig::ZERO,
51            }
52        } else {
53            self.repr.significand.signum()
54        };
55        let repr = Repr {
56            significand,
57            exponent: 0,
58        };
59        Self::new(repr, Context::new(1))
60    }
61}
62
63impl<R: Round, const B: Word> Neg for FBig<R, B> {
64    type Output = Self;
65    #[inline]
66    fn neg(mut self) -> Self::Output {
67        self.repr = self.repr.neg();
68        self
69    }
70}
71
72impl<R: Round, const B: Word> Neg for &FBig<R, B> {
73    type Output = FBig<R, B>;
74    #[inline]
75    fn neg(self) -> Self::Output {
76        self.clone().neg()
77    }
78}
79
80impl<R: Round, const B: Word> Abs for FBig<R, B> {
81    type Output = Self;
82    fn abs(mut self) -> Self::Output {
83        // flip -0 -> +0 and -inf -> +inf by toggling the special-value exponent;
84        // finite values take the absolute value of their significand.
85        if self.repr.significand.is_zero() {
86            if self.repr.exponent == -1 {
87                self.repr.exponent = 0;
88            } else if self.repr.exponent == isize::MIN {
89                self.repr.exponent = isize::MAX;
90            }
91        } else {
92            self.repr.significand = self.repr.significand.abs();
93        }
94        self
95    }
96}
97
98impl<R: Round, const B: Word> Mul<FBig<R, B>> for Sign {
99    type Output = FBig<R, B>;
100    #[inline]
101    fn mul(self, rhs: FBig<R, B>) -> Self::Output {
102        match self {
103            Sign::Positive => rhs,
104            Sign::Negative => -rhs,
105        }
106    }
107}
108
109impl<R: Round, const B: Word> Mul<Sign> for FBig<R, B> {
110    type Output = FBig<R, B>;
111    #[inline]
112    fn mul(self, rhs: Sign) -> Self::Output {
113        match rhs {
114            Sign::Positive => self,
115            Sign::Negative => -self,
116        }
117    }
118}
119
120impl<R: Round, const B: Word> MulAssign<Sign> for FBig<R, B> {
121    #[inline]
122    fn mul_assign(&mut self, rhs: Sign) {
123        if rhs == Sign::Negative {
124            self.repr = self.repr.clone().neg();
125        }
126    }
127}
128
129impl<R: Round, const B: Word> Signed for FBig<R, B> {
130    #[inline]
131    fn sign(&self) -> Sign {
132        self.repr.sign()
133    }
134}