1// Adapted from https://github.com/Alexhuszagh/rust-lexical.
2
3//! Utilities to calculate exponents.
4
5/// Convert usize into i32 without overflow.
6///
7/// This is needed to ensure when adjusting the exponent relative to
8/// the mantissa we do not overflow for comically-long exponents.
9#[inline]
10fn into_i32(value: usize) -> i32 {
11 if value > i32::max_value() as usize {
12 i32::max_value()
13 } else {
14 value as i32
15 }
16}
17
18// EXPONENT CALCULATION
19
20// Calculate the scientific notation exponent without overflow.
21//
22// For example, 0.1 would be -1, and 10 would be 1 in base 10.
23#[inline]
24pub(crate) fn scientific_exponent(
25 exponent: i32,
26 integer_digits: usize,
27 fraction_start: usize,
28) -> i32 {
29 if integer_digits == 0 {
30 let fraction_start = into_i32(fraction_start);
31 exponent.saturating_sub(fraction_start).saturating_sub(1)
32 } else {
33 let integer_shift = into_i32(integer_digits - 1);
34 exponent.saturating_add(integer_shift)
35 }
36}
37
38// Calculate the mantissa exponent without overflow.
39//
40// Remove the number of digits that contributed to the mantissa past
41// the dot, and add the number of truncated digits from the mantissa,
42// to calculate the scaling factor for the mantissa from a raw exponent.
43#[inline]
44pub(crate) fn mantissa_exponent(exponent: i32, fraction_digits: usize, truncated: usize) -> i32 {
45 if fraction_digits > truncated {
46 exponent.saturating_sub(into_i32(fraction_digits - truncated))
47 } else {
48 exponent.saturating_add(into_i32(truncated - fraction_digits))
49 }
50}
51