rust_fixed_point_decimal/
from_float.rs1use std::convert::TryFrom;
11
12use num::{traits::float::FloatCore, BigInt, One};
13use rust_fixed_point_decimal_core::ten_pow;
14
15use crate::{
16 errors::DecimalError,
17 prec_constraints::{PrecLimitCheck, True},
18 rounding::div_i128_rounded,
19 Decimal,
20};
21
22macro_rules! impl_from_float {
23 () => {
24 impl_from_float!(f32, f64);
25 };
26 ($($t:ty),*) => {
27 $(
28 impl<const P: u8> TryFrom<$t> for Decimal<P>
29 where
30 PrecLimitCheck<{ P <= crate::MAX_PREC }>: True,
31 {
32 type Error = DecimalError;
33
34 fn try_from(f: $t) -> Result<Self, Self::Error> {
35 if f.is_infinite() {
36 return Err(DecimalError::InfiniteValue);
37 }
38 if f.is_nan() {
39 return Err(DecimalError::NotANumber);
40 }
41 let (mantissa, exponent, sign) = f.integer_decode();
42 if exponent < -126 {
43 Ok(Decimal::ZERO)
44 }
45 else if exponent < 0 {
46 let numer = i128::from(sign)
47 * i128::from(mantissa)
48 * ten_pow(P);
49 let denom = i128::one() << ((-exponent) as usize);
50 let coeff = div_i128_rounded(numer, denom, None);
51 Ok(Decimal { coeff })
52 } else {
53 let mut numer = BigInt::from(mantissa);
54 numer <<= exponent as usize;
55 numer *= BigInt::from(sign) * BigInt::from(ten_pow(P));
56 match i128::try_from(numer) {
57 Err(_) => Err(DecimalError::MaxValueExceeded),
58 Ok(coeff) => Ok(Decimal { coeff }),
59 }
60 }
61 }
62 }
63 )*
64 }
65}
66
67impl_from_float!();
68
69#[cfg(test)]
70mod tests {
71 use num::traits::float::FloatCore;
72
73 use super::*;
74 use crate::MAX_PREC;
75
76 fn check_from_float<const P: u8, T>(test_data: &[(T, i128)])
77 where
78 PrecLimitCheck<{ P <= MAX_PREC }>: True,
79 T: FloatCore,
80 Decimal<P>: TryFrom<T>,
81 {
82 for (val, coeff) in test_data {
83 match Decimal::<P>::try_from(*val) {
84 Err(_) => panic!("Mismatched test data!"),
85 Ok(d) => {
86 assert_eq!(d.coeff, *coeff);
87 assert_eq!(d.precision(), P);
88 }
89 }
90 }
91 }
92
93 #[test]
94 fn test_decimal0_from_f32() {
95 let test_data = [
96 (i128::MIN as f32, i128::MIN),
97 (-289.04, -289),
98 (-2.5, -2),
99 (0.0, 0),
100 (5.2, 5),
101 ((i128::MAX / 2) as f32, i128::MAX / 2 + 1),
102 ];
103 check_from_float::<0, f32>(&test_data)
104 }
105
106 #[test]
107 fn test_decimal4_from_f32() {
108 let test_data = [
109 (-289.5, -2895000),
110 (-0.5, -5000),
111 (0.0, 0),
112 (37.0005003, 370005),
113 ];
114 check_from_float::<4, f32>(&test_data)
115 }
116
117 #[test]
118 fn test_decimal0_from_f64() {
119 let test_data = [
120 (i128::MIN as f64, i128::MIN),
121 (-289.4, -289),
122 (-2.5, -2),
123 (0.0, 0),
124 (5.2, 5),
125 ((i128::MAX / 2) as f64, i128::MAX / 2 + 1),
126 ];
127 check_from_float::<0, f64>(&test_data)
128 }
129
130 #[test]
131 fn test_decimal9_from_f64() {
132 let test_data = [
133 (-28900.000000005, -28900000000005),
134 (-5e-7, -500),
135 (1.004e-127, 0),
136 (0.0, 0),
137 (1.0005, 1000500000),
138 (37.0005000033, 37000500003),
139 ];
140 check_from_float::<9, f64>(&test_data)
141 }
142
143 #[test]
144 fn test_fail_on_f32_infinite_value() {
145 for f in [f32::infinity(), f32::neg_infinity()] {
146 let res = Decimal::<2>::try_from(f);
147 assert!(res.is_err());
148 let err = res.unwrap_err();
149 assert_eq!(err, DecimalError::InfiniteValue);
150 }
151 }
152
153 #[test]
154 fn test_fail_on_f64_infinite_value() {
155 for f in [f64::infinity(), f64::neg_infinity()] {
156 let res = Decimal::<2>::try_from(f);
157 assert!(res.is_err());
158 let err = res.unwrap_err();
159 assert_eq!(err, DecimalError::InfiniteValue);
160 }
161 }
162
163 #[test]
164 fn test_fail_on_f32_nan() {
165 let f = f32::nan();
166 let res = Decimal::<2>::try_from(f);
167 assert!(res.is_err());
168 let err = res.unwrap_err();
169 assert_eq!(err, DecimalError::NotANumber);
170 }
171
172 #[test]
173 fn test_fail_on_f64_nan() {
174 let f = f64::nan();
175 let res = Decimal::<7>::try_from(f);
176 assert!(res.is_err());
177 let err = res.unwrap_err();
178 assert_eq!(err, DecimalError::NotANumber);
179 }
180}