Skip to main content

core/num/imp/dec2flt/
lemire.rs

1//! Implementation of the Eisel-Lemire algorithm.
2
3use dec2flt::common::BiasedFp;
4use dec2flt::table::{LARGEST_POWER_OF_FIVE, POWER_OF_FIVE_128, SMALLEST_POWER_OF_FIVE};
5
6use crate::num::imp::{Float, dec2flt};
7
8/// Compute w * 10^q using an extended-precision float representation.
9///
10/// Fast conversion of a the significant digits and decimal exponent
11/// a float to an extended representation with a binary float. This
12/// algorithm will accurately parse the vast majority of cases,
13/// and uses a 128-bit representation (with a fallback 192-bit
14/// representation).
15///
16/// This algorithm scales the exponent by the decimal exponent
17/// using pre-computed powers-of-5, and calculates if the
18/// representation can be unambiguously rounded to the nearest
19/// machine float. Near-halfway cases are not handled here,
20/// and are represented by a negative, biased binary exponent.
21///
22/// The algorithm is described in detail in "Daniel Lemire, Number Parsing
23/// at a Gigabyte per Second" in section 5, "Fast Algorithm", and
24/// section 6, "Exact Numbers And Ties", available online:
25/// <https://arxiv.org/abs/2101.11408.pdf>.
26pub fn compute_float<F: Float>(q: i64, mut w: u64) -> BiasedFp {
27    let fp_zero = BiasedFp::zero_pow2(0);
28    let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER);
29    let fp_error = BiasedFp::zero_pow2(-1);
30
31    // Short-circuit if the value can only be a literal 0 or infinity.
32    if w == 0 || q < F::SMALLEST_POWER_OF_TEN as i64 {
33        return fp_zero;
34    } else if q > F::LARGEST_POWER_OF_TEN as i64 {
35        return fp_inf;
36    }
37    // Normalize our significant digits, so the most-significant bit is set.
38    let lz = w.leading_zeros();
39    w <<= lz;
40    let (lo, hi) = compute_product_approx(q, w, F::SIG_BITS as usize + 3);
41    if lo == 0xFFFF_FFFF_FFFF_FFFF {
42        // If we have failed to approximate w x 5^-q with our 128-bit value.
43        // Since the addition of 1 could lead to an overflow which could then
44        // round up over the half-way point, this can lead to improper rounding
45        // of a float.
46        //
47        // However, this can only occur if q ∈ [-27, 55]. The upper bound of q
48        // is 55 because 5^55 < 2^128, however, this can only happen if 5^q > 2^64,
49        // since otherwise the product can be represented in 64-bits, producing
50        // an exact result. For negative exponents, rounding-to-even can
51        // only occur if 5^-q < 2^64.
52        //
53        // For detailed explanations of rounding for negative exponents, see
54        // <https://arxiv.org/pdf/2101.11408.pdf#section.9.1>. For detailed
55        // explanations of rounding for positive exponents, see
56        // <https://arxiv.org/pdf/2101.11408.pdf#section.8>.
57        let inside_safe_exponent = (q >= -27) && (q <= 55);
58        if !inside_safe_exponent {
59            return fp_error;
60        }
61    }
62    let upperbit = (hi >> 63) as i32;
63    let mut mantissa = hi >> (upperbit + 64 - F::SIG_BITS as i32 - 3);
64    let mut power2 = power(q as i32) + upperbit - lz as i32 - F::EXP_MIN + 1;
65    if power2 <= 0 {
66        if -power2 + 1 >= 64 {
67            // Have more than 64 bits below the minimum exponent, must be 0.
68            return fp_zero;
69        }
70        // Have a subnormal value.
71        mantissa >>= -power2 + 1;
72        mantissa += mantissa & 1;
73        mantissa >>= 1;
74        power2 = (mantissa >= (1_u64 << F::SIG_BITS)) as i32;
75        return BiasedFp { m: mantissa, p_biased: power2 };
76    }
77    // Need to handle rounding ties. Normally, we need to round up,
78    // but if we fall right in between and we have an even basis, we
79    // need to round down.
80    //
81    // This will only occur if:
82    //  1. The lower 64 bits of the 128-bit representation is 0.
83    //      IE, 5^q fits in single 64-bit word.
84    //  2. The least-significant bit prior to truncated mantissa is odd.
85    //  3. All the bits truncated when shifting to mantissa bits + 1 are 0.
86    //
87    // Or, we may fall between two floats: we are exactly halfway.
88    if lo <= 1
89        && q >= F::MIN_EXPONENT_ROUND_TO_EVEN as i64
90        && q <= F::MAX_EXPONENT_ROUND_TO_EVEN as i64
91        && mantissa & 0b11 == 0b01
92        && (mantissa << (upperbit + 64 - F::SIG_BITS as i32 - 3)) == hi
93    {
94        // Zero the lowest bit, so we don't round up.
95        mantissa &= !1_u64;
96    }
97    // Round-to-even, then shift the significant digits into place.
98    mantissa += mantissa & 1;
99    mantissa >>= 1;
100    if mantissa >= (2_u64 << F::SIG_BITS) {
101        // Rounding up overflowed, so the carry bit is set. Set the
102        // mantissa to 1 (only the implicit, hidden bit is set) and
103        // increase the exponent.
104        mantissa = 1_u64 << F::SIG_BITS;
105        power2 += 1;
106    }
107    // Zero out the hidden bit.
108    mantissa &= !(1_u64 << F::SIG_BITS);
109    if power2 >= F::INFINITE_POWER {
110        // Exponent is above largest normal value, must be infinite.
111        return fp_inf;
112    }
113    BiasedFp { m: mantissa, p_biased: power2 }
114}
115
116/// Calculate a base 2 exponent from a decimal exponent.
117/// This uses a pre-computed integer approximation for
118/// log2(10), where 217706 / 2^16 is accurate for the
119/// entire range of non-finite decimal exponents.
120#[inline]
121fn power(q: i32) -> i32 {
122    (q.wrapping_mul(152_170 + 65536) >> 16) + 63
123}
124
125#[inline]
126fn full_multiplication(a: u64, b: u64) -> (u64, u64) {
127    let r = (a as u128) * (b as u128);
128    (r as u64, (r >> 64) as u64)
129}
130
131// This will compute or rather approximate w * 5**q and return a pair of 64-bit words
132// approximating the result, with the "high" part corresponding to the most significant
133// bits and the low part corresponding to the least significant bits.
134fn compute_product_approx(q: i64, w: u64, precision: usize) -> (u64, u64) {
135    if true {
    if !(q >= SMALLEST_POWER_OF_FIVE as i64) {
        crate::panicking::panic("assertion failed: q >= SMALLEST_POWER_OF_FIVE as i64")
    };
};debug_assert!(q >= SMALLEST_POWER_OF_FIVE as i64);
136    if true {
    if !(q <= LARGEST_POWER_OF_FIVE as i64) {
        crate::panicking::panic("assertion failed: q <= LARGEST_POWER_OF_FIVE as i64")
    };
};debug_assert!(q <= LARGEST_POWER_OF_FIVE as i64);
137    if true {
    if !(precision <= 64) {
        crate::panicking::panic("assertion failed: precision <= 64")
    };
};debug_assert!(precision <= 64);
138
139    let mask = if precision < 64 {
140        0xFFFF_FFFF_FFFF_FFFF_u64 >> precision
141    } else {
142        0xFFFF_FFFF_FFFF_FFFF_u64
143    };
144
145    // 5^q < 2^64, then the multiplication always provides an exact value.
146    // That means whenever we need to round ties to even, we always have
147    // an exact value.
148    let index = (q - SMALLEST_POWER_OF_FIVE as i64) as usize;
149    let (lo5, hi5) = POWER_OF_FIVE_128[index];
150    // Only need one multiplication as long as there is 1 zero but
151    // in the explicit mantissa bits, +1 for the hidden bit, +1 to
152    // determine the rounding direction, +1 for if the computed
153    // product has a leading zero.
154    let (mut first_lo, mut first_hi) = full_multiplication(w, lo5);
155    if first_hi & mask == mask {
156        // Need to do a second multiplication to get better precision
157        // for the lower product. This will always be exact
158        // where q is < 55, since 5^55 < 2^128. If this wraps,
159        // then we need to round up the hi product.
160        let (_, second_hi) = full_multiplication(w, hi5);
161        first_lo = first_lo.wrapping_add(second_hi);
162        if second_hi > first_lo {
163            first_hi += 1;
164        }
165    }
166    (first_lo, first_hi)
167}