Skip to main content

dashu_float/third_party/
num_traits.rs

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