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<const B: Word> Neg for Repr<B> {
64    type Output = Self;
65    #[inline]
66    fn neg(self) -> Self::Output {
67        Repr::neg(self)
68    }
69}
70
71impl<R: Round, const B: Word> Neg for FBig<R, B> {
72    type Output = Self;
73    #[inline]
74    fn neg(mut self) -> Self::Output {
75        self.repr = self.repr.neg();
76        self
77    }
78}
79
80impl<R: Round, const B: Word> Neg for &FBig<R, B> {
81    type Output = FBig<R, B>;
82    #[inline]
83    fn neg(self) -> Self::Output {
84        self.clone().neg()
85    }
86}
87
88impl<R: Round, const B: Word> Abs for FBig<R, B> {
89    type Output = Self;
90    fn abs(mut self) -> Self::Output {
91        // flip -0 -> +0 and -inf -> +inf by toggling the special-value exponent;
92        // finite values take the absolute value of their significand.
93        if self.repr.significand.is_zero() {
94            if self.repr.exponent == -1 {
95                self.repr.exponent = 0;
96            } else if self.repr.exponent == isize::MIN {
97                self.repr.exponent = isize::MAX;
98            }
99        } else {
100            self.repr.significand = self.repr.significand.abs();
101        }
102        self
103    }
104}
105
106impl<R: Round, const B: Word> Mul<FBig<R, B>> for Sign {
107    type Output = FBig<R, B>;
108    #[inline]
109    fn mul(self, rhs: FBig<R, B>) -> Self::Output {
110        match self {
111            Sign::Positive => rhs,
112            Sign::Negative => -rhs,
113        }
114    }
115}
116
117impl<R: Round, const B: Word> Mul<Sign> for FBig<R, B> {
118    type Output = FBig<R, B>;
119    #[inline]
120    fn mul(self, rhs: Sign) -> Self::Output {
121        match rhs {
122            Sign::Positive => self,
123            Sign::Negative => -self,
124        }
125    }
126}
127
128impl<R: Round, const B: Word> MulAssign<Sign> for FBig<R, B> {
129    #[inline]
130    fn mul_assign(&mut self, rhs: Sign) {
131        if rhs == Sign::Negative {
132            self.repr = self.repr.clone().neg();
133        }
134    }
135}
136
137impl<R: Round, const B: Word> Signed for FBig<R, B> {
138    #[inline]
139    fn sign(&self) -> Sign {
140        self.repr.sign()
141    }
142}