1 //! Utilities to calculate exponents.
2 
3 /// Convert usize into i32 without overflow.
4 ///
5 /// This is needed to ensure when adjusting the exponent relative to
6 /// the mantissa we do not overflow for comically-long exponents.
7 #[inline]
into_i32(value: usize) -> i328 fn into_i32(value: usize) -> i32 {
9     if value > i32::max_value() as usize {
10         i32::max_value()
11     } else {
12         value as i32
13     }
14 }
15 
16 // EXPONENT CALCULATION
17 
18 // Calculate the scientific notation exponent without overflow.
19 //
20 // For example, 0.1 would be -1, and 10 would be 1 in base 10.
21 #[inline]
scientific_exponent( exponent: i32, integer_digits: usize, fraction_start: usize, ) -> i3222 pub(crate) fn scientific_exponent(
23     exponent: i32,
24     integer_digits: usize,
25     fraction_start: usize,
26 ) -> i32 {
27     if integer_digits == 0 {
28         let fraction_start = into_i32(fraction_start);
29         exponent.saturating_sub(fraction_start).saturating_sub(1)
30     } else {
31         let integer_shift = into_i32(integer_digits - 1);
32         exponent.saturating_add(integer_shift)
33     }
34 }
35 
36 // Calculate the mantissa exponent without overflow.
37 //
38 // Remove the number of digits that contributed to the mantissa past
39 // the dot, and add the number of truncated digits from the mantissa,
40 // to calculate the scaling factor for the mantissa from a raw exponent.
41 #[inline]
mantissa_exponent(exponent: i32, fraction_digits: usize, truncated: usize) -> i3242 pub(crate) fn mantissa_exponent(exponent: i32, fraction_digits: usize, truncated: usize) -> i32 {
43     if fraction_digits > truncated {
44         exponent.saturating_sub(into_i32(fraction_digits - truncated))
45     } else {
46         exponent.saturating_add(into_i32(truncated - fraction_digits))
47     }
48 }
49 
50 // TESTS
51 // -----
52 
53 #[cfg(test)]
54 mod test {
55     use super::*;
56 
57     #[test]
scientific_exponent_test()58     fn scientific_exponent_test() {
59         // 0 digits in the integer
60         assert_eq!(scientific_exponent(0, 0, 5), -6);
61         assert_eq!(scientific_exponent(10, 0, 5), 4);
62         assert_eq!(scientific_exponent(-10, 0, 5), -16);
63 
64         // >0 digits in the integer
65         assert_eq!(scientific_exponent(0, 1, 5), 0);
66         assert_eq!(scientific_exponent(0, 2, 5), 1);
67         assert_eq!(scientific_exponent(0, 2, 20), 1);
68         assert_eq!(scientific_exponent(10, 2, 20), 11);
69         assert_eq!(scientific_exponent(-10, 2, 20), -9);
70 
71         // Underflow
72         assert_eq!(scientific_exponent(i32::min_value(), 0, 0), i32::min_value());
73         assert_eq!(scientific_exponent(i32::min_value(), 0, 5), i32::min_value());
74 
75         // Overflow
76         assert_eq!(scientific_exponent(i32::max_value(), 0, 0), i32::max_value() - 1);
77         assert_eq!(scientific_exponent(i32::max_value(), 5, 0), i32::max_value());
78     }
79 
80     #[test]
mantissa_exponent_test()81     fn mantissa_exponent_test() {
82         assert_eq!(mantissa_exponent(10, 5, 0), 5);
83         assert_eq!(mantissa_exponent(0, 5, 0), -5);
84         assert_eq!(mantissa_exponent(i32::max_value(), 5, 0), i32::max_value() - 5);
85         assert_eq!(mantissa_exponent(i32::max_value(), 0, 5), i32::max_value());
86         assert_eq!(mantissa_exponent(i32::min_value(), 5, 0), i32::min_value());
87         assert_eq!(mantissa_exponent(i32::min_value(), 0, 5), i32::min_value() + 5);
88     }
89 }
90