Skip to main content

dashu_float/third_party/
num_traits.rs

1//! Implement num-traits traits.
2
3use crate::{
4    fbig::FBig,
5    round::{ErrorBounds, Round},
6};
7use dashu_base::{Abs, DivEuclid, ParseError, RemEuclid, Sign};
8use dashu_int::{IBig, Word};
9use num_traits_v02 as num_traits;
10
11impl<R: Round, const B: Word> num_traits::Zero for FBig<R, B> {
12    #[inline]
13    fn zero() -> Self {
14        FBig::ZERO
15    }
16    #[inline]
17    fn is_zero(&self) -> bool {
18        // Numerically zero: both +0 and -0 are the additive identity.
19        self.repr.is_pos_zero() || self.repr.is_neg_zero()
20    }
21}
22
23impl<R: Round, const B: Word> num_traits::One for FBig<R, B> {
24    #[inline]
25    fn one() -> Self {
26        FBig::ONE
27    }
28    #[inline]
29    fn is_one(&self) -> bool {
30        self.repr.is_one()
31    }
32}
33
34macro_rules! impl_from_primitive_int {
35    ($t:ty, $method:ident) => {
36        #[inline]
37        fn $method(n: $t) -> Option<Self> {
38            Some(FBig::from(n))
39        }
40    };
41}
42
43impl<R: Round, const B: Word> num_traits::FromPrimitive for FBig<R, B> {
44    impl_from_primitive_int!(i8, from_i8);
45    impl_from_primitive_int!(i16, from_i16);
46    impl_from_primitive_int!(i32, from_i32);
47    impl_from_primitive_int!(i64, from_i64);
48    impl_from_primitive_int!(i128, from_i128);
49    impl_from_primitive_int!(isize, from_isize);
50    impl_from_primitive_int!(u8, from_u8);
51    impl_from_primitive_int!(u16, from_u16);
52    impl_from_primitive_int!(u32, from_u32);
53    impl_from_primitive_int!(u64, from_u64);
54    impl_from_primitive_int!(u128, from_u128);
55    impl_from_primitive_int!(usize, from_usize);
56
57    #[inline]
58    fn from_f32(f: f32) -> Option<Self> {
59        match FBig::<R, 2>::try_from(f) {
60            Ok(val) => Some(val.with_base::<B>().value()),
61            Err(_) => None,
62        }
63    }
64    #[inline]
65    fn from_f64(f: f64) -> Option<Self> {
66        match FBig::<R, 2>::try_from(f) {
67            Ok(val) => Some(val.with_base::<B>().value()),
68            Err(_) => None,
69        }
70    }
71}
72
73macro_rules! impl_to_primitive_int {
74    ($t:ty, $method:ident) => {
75        #[inline]
76        fn $method(&self) -> Option<$t> {
77            num_traits::ToPrimitive::$method(&self.to_int().value())
78        }
79    };
80}
81
82impl<R: Round, const B: Word> num_traits::ToPrimitive for FBig<R, B> {
83    impl_to_primitive_int!(i8, to_i8);
84    impl_to_primitive_int!(i16, to_i16);
85    impl_to_primitive_int!(i32, to_i32);
86    impl_to_primitive_int!(i64, to_i64);
87    impl_to_primitive_int!(i128, to_i128);
88    impl_to_primitive_int!(isize, to_isize);
89    impl_to_primitive_int!(u8, to_u8);
90    impl_to_primitive_int!(u16, to_u16);
91    impl_to_primitive_int!(u32, to_u32);
92    impl_to_primitive_int!(u64, to_u64);
93    impl_to_primitive_int!(u128, to_u128);
94    impl_to_primitive_int!(usize, to_usize);
95
96    #[inline]
97    fn to_f32(&self) -> Option<f32> {
98        Some(self.to_f32().value())
99    }
100    #[inline]
101    fn to_f64(&self) -> Option<f64> {
102        Some(self.to_f64().value())
103    }
104}
105
106impl<R: ErrorBounds, const B: Word> num_traits::Pow<IBig> for FBig<R, B> {
107    type Output = FBig<R, B>;
108
109    fn pow(self, rhs: IBig) -> Self {
110        self.powi(rhs)
111    }
112}
113impl<R: ErrorBounds, const B: Word> num_traits::Pow<IBig> for &FBig<R, B> {
114    type Output = FBig<R, B>;
115
116    fn pow(self, rhs: IBig) -> FBig<R, B> {
117        self.powi(rhs)
118    }
119}
120impl<R: ErrorBounds, const B: Word> num_traits::Pow<&FBig<R, B>> for FBig<R, B> {
121    type Output = FBig<R, B>;
122
123    fn pow(self, rhs: &Self) -> Self {
124        self.powf(rhs)
125    }
126}
127impl<R: ErrorBounds, const B: Word> num_traits::Pow<&FBig<R, B>> for &FBig<R, B> {
128    type Output = FBig<R, B>;
129
130    fn pow(self, rhs: &FBig<R, B>) -> FBig<R, B> {
131        self.powf(rhs)
132    }
133}
134
135impl<R: Round, const B: Word> num_traits::Num for FBig<R, B> {
136    type FromStrRadixErr = ParseError;
137    #[inline]
138    fn from_str_radix(s: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
139        // the conversion might a fail with 16-bit words.
140        #[allow(clippy::unnecessary_fallible_conversions, clippy::useless_conversion)]
141        let r: Word = radix.try_into().map_err(|_| ParseError::UnsupportedRadix)?;
142        if r == B {
143            s.parse()
144        } else {
145            Err(ParseError::UnsupportedRadix)
146        }
147    }
148}
149
150impl<R: Round, const B: Word> num_traits::Euclid for FBig<R, B> {
151    #[inline]
152    fn div_euclid(&self, v: &Self) -> Self {
153        DivEuclid::div_euclid(self, v).into()
154    }
155    #[inline]
156    fn rem_euclid(&self, v: &Self) -> Self {
157        RemEuclid::rem_euclid(self, v)
158    }
159}
160
161impl<R: Round, const B: Word> num_traits::Signed for FBig<R, B> {
162    #[inline]
163    fn abs(&self) -> Self {
164        Abs::abs(self.clone())
165    }
166
167    #[inline]
168    fn abs_sub(&self, other: &Self) -> Self {
169        Abs::abs(self - other)
170    }
171
172    #[inline]
173    fn signum(&self) -> Self {
174        FBig::signum(self)
175    }
176
177    #[inline]
178    fn is_positive(&self) -> bool {
179        self.repr.sign() == Sign::Positive
180    }
181
182    #[inline]
183    fn is_negative(&self) -> bool {
184        self.repr.sign() == Sign::Negative
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use super::num_traits::{FromPrimitive, One, Zero};
191    use crate::DBig;
192
193    #[test]
194    fn test_01() {
195        assert_eq!(DBig::from(0), DBig::zero());
196        assert_eq!(DBig::from(1), DBig::one());
197
198        assert!(DBig::from(0).is_zero());
199        assert!(!DBig::from(0).is_one());
200        assert!(!DBig::from(1).is_zero());
201        assert!(DBig::from(1).is_one());
202    }
203
204    #[test]
205    fn test_from() {
206        assert_eq!(DBig::from_usize(1), Some(DBig::one()));
207        assert_eq!(DBig::from_isize(-1), Some(-DBig::one()));
208    }
209}