1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
use crate::{
ops::Zero,
power_table::{
power_of_10, rdiv_by_exponent_10, MAX_EXPONENT_5, NEXT_EXPONENT_10, POWERS_OF_10,
POWERS_OF_5,
},
ConvertError, FixedPoint, Precision,
};
macro_rules! impl_try_from_f64 {
($layout:tt) => {
impl<P: Precision> TryFrom<f64> for FixedPoint<$layout, P> {
type Error = ConvertError;
/// Implementation courtesy of [`rust_decimal` crate][rust_decimal]
///
/// [rust_decimal]: https://github.com/paupino/rust-decimal/blob/2de2a6dd2f385e98c4019ebe38b5c6de5fef6cba/src/decimal.rs#L2059
fn try_from(value: f64) -> Result<Self, Self::Error> {
if !value.is_finite() {
return Err(ConvertError::new("not finite"));
}
// f64 is being broken up by bits i.e. 1/11/52 (sign, biased_exponent, mantissa)
// See https://en.wikipedia.org/wiki/IEEE_754-1985
// n = (-1)^sign * 2^exp * significand
// fixnum stores it differently: n = significand * 10^(-PRECISION)
let raw = value.to_bits();
let positive = (raw >> 63) == 0;
let biased_exponent = ((raw >> 52) & 0x7FF) as i32;
let mut bits = (raw & 0x000F_FFFF_FFFF_FFFF) as u128;
// Handle the special zero case
if biased_exponent == 0 && bits == 0 {
return Ok(Self::ZERO);
}
// Get the bits and exponent2
let mut exponent2 = if biased_exponent == 0 {
// Denormalized number
-1022
} else {
// Add extra hidden bit to mantissa
bits |= 0x0010_0000_0000_0000;
biased_exponent - 1023
};
// The act of copying a significand as integer bits is equivalent to shifting
// left the significand 52 bits. The exponent is reduced to compensate.
exponent2 -= 52;
// 2^exponent2 = 10^exponent2 / 5^exponent2 =
// = 10^exponent2 * 5^(-exponent2)
let mut exponent5 = -exponent2;
let mut exponent10 = exponent2; // Ultimately, we want this for the scale
if exponent5 > 0 {
// Divide significand by 2 as much as possible without losing precision
let excess_exponent2 = bits.trailing_zeros().min(exponent5 as u32) as i32;
exponent10 += excess_exponent2;
exponent5 -= excess_exponent2;
bits >>= excess_exponent2;
if exponent5 > 0 {
// The significand is no more divisible by 2. Therefore the significand should
// be multiplied by 5, unless the multiplication overflows.
let lz = bits.leading_zeros() as usize;
let reduced_exponent5 = if lz == 0 {
0
} else {
let multiplier_exponent5 = exponent5.min(MAX_EXPONENT_5[lz - 1] as i32);
bits *= POWERS_OF_5[multiplier_exponent5 as usize];
if let (true, Some(b)) =
(multiplier_exponent5 < exponent5, bits.checked_mul(5))
{
bits = b;
multiplier_exponent5 + 1
} else {
multiplier_exponent5
}
};
if reduced_exponent5 == 0 {
// Multiplication by 5 overflows. The significand should be divided
// by 2, and therefore will lose significant digits.
exponent10 += 1;
exponent5 -= 1;
bits >>= 1;
} else {
exponent5 -= reduced_exponent5;
}
while exponent5 > 0 {
if bits & 1 == 0 {
exponent10 += 1;
exponent5 -= 1;
bits >>= 1;
} else {
if let Some(b) = bits.checked_mul(5) {
exponent5 -= 1;
bits = b;
} else {
// Multiplication by 5 overflows. The significand should be divided
// by 2, and therefore will lose significant digits.
exponent10 += 1;
exponent5 -= 1;
bits >>= 1;
}
}
}
}
}
// In order to divide the value by 5, it is best to multiply by 2/10.
// Therefore, exponent10 is decremented, and the significand should be multiplied by 2.
while exponent5 < 0 {
const MOST_SIGNIFICANT_BIT: u128 = !(u128::MAX >> 1);
bits = if bits & MOST_SIGNIFICANT_BIT == 0 {
// No far left bit, the significand can withstand a shift-left without overflowing
exponent10 -= 1;
exponent5 += 1;
bits << 1
} else {
// The significand would overflow if shifted. Therefore it should be
// directly divided by 5. This will lose significant digits, unless
// by chance the significand happens to be divisible by 5.
exponent5 += 1;
bits / 5
};
}
// At this point, the significand has assimilated the exponent5
// This step is required in order to remove excess bits of precision from the
// end of the bit representation, down to the precision guaranteed by the
// floating point number
// Guaranteed to about 16 dp
let prefix = bits >> 52;
if exponent10 < 0 && prefix > 0 {
let lz = (bits.leading_zeros() + 52) as usize;
let mut divisor_exponent_10 = NEXT_EXPONENT_10[lz] as i32;
let divisor = power_of_10(divisor_exponent_10 as u32).unwrap();
if prefix >= divisor {
divisor_exponent_10 = NEXT_EXPONENT_10[lz - 1] as i32;
}
let divisor_exponent_10 = divisor_exponent_10.min(-exponent10 as i32);
let (divisor, remainder) = POWERS_OF_10[divisor_exponent_10 as usize];
let res = bits / divisor;
bits = if bits % divisor > remainder {
res + 1
} else {
res
};
exponent10 += divisor_exponent_10;
}
// exponent10 must equal to -PRECISION, so the significand must be scaled up or down appropriately.
if exponent10 > -Self::PRECISION {
// In order to bring exponent10 down, the significand should be
// multiplied by 10 to compensate. If the exponent10 is too big, this
// will cause the significand to overflow.
bits = power_of_10((exponent10 + Self::PRECISION) as u32)
.and_then(|multiplier| bits.checked_mul(multiplier))
.ok_or_else(|| ConvertError::new("too big number"))?;
} else if exponent10 < -Self::PRECISION {
// In order to bring exponent up to -PRECISION, the significand should
// be divided by 10 to compensate. If the exponent10 is too small, this
// will cause the significand to underflow and become 0.
bits = rdiv_by_exponent_10(bits, (-Self::PRECISION - exponent10) as u32);
}
let bits: $layout = bits
.try_into()
.map_err(|_| ConvertError::new("too big number"))?;
if positive {
Ok(Self::from_bits(bits))
} else {
bits.checked_neg()
.map(Self::from_bits)
.ok_or_else(|| ConvertError::new("too big number"))
}
}
}
};
}
// TODO: pass attrs to doc.
#[cfg(feature = "i16")]
impl_try_from_f64!(i16);
#[cfg(feature = "i32")]
impl_try_from_f64!(i32);
#[cfg(feature = "i64")]
impl_try_from_f64!(i64);
#[cfg(feature = "i128")]
impl_try_from_f64!(i128);