summaryrefslogtreecommitdiffstats
path: root/third_party/rust/minimal-lexical/src/slow.rs
blob: 59d526ba42343f4222f8ab73dcbd7e4cd7893088 (plain)
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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
//! Slow, fallback cases where we cannot unambiguously round a float.
//!
//! This occurs when we cannot determine the exact representation using
//! both the fast path (native) cases nor the Lemire/Bellerophon algorithms,
//! and therefore must fallback to a slow, arbitrary-precision representation.

#![doc(hidden)]

use crate::bigint::{Bigint, Limb, LIMB_BITS};
use crate::extended_float::{extended_to_float, ExtendedFloat};
use crate::num::Float;
use crate::number::Number;
use crate::rounding::{round, round_down, round_nearest_tie_even};
use core::cmp;

// ALGORITHM
// ---------

/// Parse the significant digits and biased, binary exponent of a float.
///
/// This is a fallback algorithm that uses a big-integer representation
/// of the float, and therefore is considerably slower than faster
/// approximations. However, it will always determine how to round
/// the significant digits to the nearest machine float, allowing
/// use to handle near half-way cases.
///
/// Near half-way cases are halfway between two consecutive machine floats.
/// For example, the float `16777217.0` has a bitwise representation of
/// `100000000000000000000000 1`. Rounding to a single-precision float,
/// the trailing `1` is truncated. Using round-nearest, tie-even, any
/// value above `16777217.0` must be rounded up to `16777218.0`, while
/// any value before or equal to `16777217.0` must be rounded down
/// to `16777216.0`. These near-halfway conversions therefore may require
/// a large number of digits to unambiguously determine how to round.
#[inline]
pub fn slow<'a, F, Iter1, Iter2>(
    num: Number,
    fp: ExtendedFloat,
    integer: Iter1,
    fraction: Iter2,
) -> ExtendedFloat
where
    F: Float,
    Iter1: Iterator<Item = &'a u8> + Clone,
    Iter2: Iterator<Item = &'a u8> + Clone,
{
    // Ensure our preconditions are valid:
    //  1. The significant digits are not shifted into place.
    debug_assert!(fp.mant & (1 << 63) != 0);

    // This assumes the sign bit has already been parsed, and we're
    // starting with the integer digits, and the float format has been
    // correctly validated.
    let sci_exp = scientific_exponent(&num);

    // We have 2 major algorithms we use for this:
    //  1. An algorithm with a finite number of digits and a positive exponent.
    //  2. An algorithm with a finite number of digits and a negative exponent.
    let (bigmant, digits) = parse_mantissa(integer, fraction, F::MAX_DIGITS);
    let exponent = sci_exp + 1 - digits as i32;
    if exponent >= 0 {
        positive_digit_comp::<F>(bigmant, exponent)
    } else {
        negative_digit_comp::<F>(bigmant, fp, exponent)
    }
}

/// Generate the significant digits with a positive exponent relative to mantissa.
pub fn positive_digit_comp<F: Float>(mut bigmant: Bigint, exponent: i32) -> ExtendedFloat {
    // Simple, we just need to multiply by the power of the radix.
    // Now, we can calculate the mantissa and the exponent from this.
    // The binary exponent is the binary exponent for the mantissa
    // shifted to the hidden bit.
    bigmant.pow(10, exponent as u32).unwrap();

    // Get the exact representation of the float from the big integer.
    // hi64 checks **all** the remaining bits after the mantissa,
    // so it will check if **any** truncated digits exist.
    let (mant, is_truncated) = bigmant.hi64();
    let exp = bigmant.bit_length() as i32 - 64 + F::EXPONENT_BIAS;
    let mut fp = ExtendedFloat {
        mant,
        exp,
    };

    // Shift the digits into position and determine if we need to round-up.
    round::<F, _>(&mut fp, |f, s| {
        round_nearest_tie_even(f, s, |is_odd, is_halfway, is_above| {
            is_above || (is_halfway && is_truncated) || (is_odd && is_halfway)
        });
    });
    fp
}

/// Generate the significant digits with a negative exponent relative to mantissa.
///
/// This algorithm is quite simple: we have the significant digits `m1 * b^N1`,
/// where `m1` is the bigint mantissa, `b` is the radix, and `N1` is the radix
/// exponent. We then calculate the theoretical representation of `b+h`, which
/// is `m2 * 2^N2`, where `m2` is the bigint mantissa and `N2` is the binary
/// exponent. If we had infinite, efficient floating precision, this would be
/// equal to `m1 / b^-N1` and then compare it to `m2 * 2^N2`.
///
/// Since we cannot divide and keep precision, we must multiply the other:
/// if we want to do `m1 / b^-N1 >= m2 * 2^N2`, we can do
/// `m1 >= m2 * b^-N1 * 2^N2` Going to the decimal case, we can show and example
/// and simplify this further: `m1 >= m2 * 2^N2 * 10^-N1`. Since we can remove
/// a power-of-two, this is `m1 >= m2 * 2^(N2 - N1) * 5^-N1`. Therefore, if
/// `N2 - N1 > 0`, we need have `m1 >= m2 * 2^(N2 - N1) * 5^-N1`, otherwise,
/// we have `m1 * 2^(N1 - N2) >= m2 * 5^-N1`, where the resulting exponents
/// are all positive.
///
/// This allows us to compare both floats using integers efficiently
/// without any loss of precision.
#[allow(clippy::comparison_chain)]
pub fn negative_digit_comp<F: Float>(
    bigmant: Bigint,
    mut fp: ExtendedFloat,
    exponent: i32,
) -> ExtendedFloat {
    // Ensure our preconditions are valid:
    //  1. The significant digits are not shifted into place.
    debug_assert!(fp.mant & (1 << 63) != 0);

    // Get the significant digits and radix exponent for the real digits.
    let mut real_digits = bigmant;
    let real_exp = exponent;
    debug_assert!(real_exp < 0);

    // Round down our extended-precision float and calculate `b`.
    let mut b = fp;
    round::<F, _>(&mut b, round_down);
    let b = extended_to_float::<F>(b);

    // Get the significant digits and the binary exponent for `b+h`.
    let theor = bh(b);
    let mut theor_digits = Bigint::from_u64(theor.mant);
    let theor_exp = theor.exp;

    // We need to scale the real digits and `b+h` digits to be the same
    // order. We currently have `real_exp`, in `radix`, that needs to be
    // shifted to `theor_digits` (since it is negative), and `theor_exp`
    // to either `theor_digits` or `real_digits` as a power of 2 (since it
    // may be positive or negative). Try to remove as many powers of 2
    // as possible. All values are relative to `theor_digits`, that is,
    // reflect the power you need to multiply `theor_digits` by.
    //
    // Both are on opposite-sides of equation, can factor out a
    // power of two.
    //
    // Example: 10^-10, 2^-10   -> ( 0, 10, 0)
    // Example: 10^-10, 2^-15   -> (-5, 10, 0)
    // Example: 10^-10, 2^-5    -> ( 5, 10, 0)
    // Example: 10^-10, 2^5     -> (15, 10, 0)
    let binary_exp = theor_exp - real_exp;
    let halfradix_exp = -real_exp;
    if halfradix_exp != 0 {
        theor_digits.pow(5, halfradix_exp as u32).unwrap();
    }
    if binary_exp > 0 {
        theor_digits.pow(2, binary_exp as u32).unwrap();
    } else if binary_exp < 0 {
        real_digits.pow(2, (-binary_exp) as u32).unwrap();
    }

    // Compare our theoretical and real digits and round nearest, tie even.
    let ord = real_digits.data.cmp(&theor_digits.data);
    round::<F, _>(&mut fp, |f, s| {
        round_nearest_tie_even(f, s, |is_odd, _, _| {
            // Can ignore `is_halfway` and `is_above`, since those were
            // calculates using less significant digits.
            match ord {
                cmp::Ordering::Greater => true,
                cmp::Ordering::Less => false,
                cmp::Ordering::Equal if is_odd => true,
                cmp::Ordering::Equal => false,
            }
        });
    });
    fp
}

/// Add a digit to the temporary value.
macro_rules! add_digit {
    ($c:ident, $value:ident, $counter:ident, $count:ident) => {{
        let digit = $c - b'0';
        $value *= 10 as Limb;
        $value += digit as Limb;

        // Increment our counters.
        $counter += 1;
        $count += 1;
    }};
}

/// Add a temporary value to our mantissa.
macro_rules! add_temporary {
    // Multiply by the small power and add the native value.
    (@mul $result:ident, $power:expr, $value:expr) => {
        $result.data.mul_small($power).unwrap();
        $result.data.add_small($value).unwrap();
    };

    // # Safety
    //
    // Safe is `counter <= step`, or smaller than the table size.
    ($format:ident, $result:ident, $counter:ident, $value:ident) => {
        if $counter != 0 {
            // SAFETY: safe, since `counter <= step`, or smaller than the table size.
            let small_power = unsafe { f64::int_pow_fast_path($counter, 10) };
            add_temporary!(@mul $result, small_power as Limb, $value);
            $counter = 0;
            $value = 0;
        }
    };

    // Add a temporary where we won't read the counter results internally.
    //
    // # Safety
    //
    // Safe is `counter <= step`, or smaller than the table size.
    (@end $format:ident, $result:ident, $counter:ident, $value:ident) => {
        if $counter != 0 {
            // SAFETY: safe, since `counter <= step`, or smaller than the table size.
            let small_power = unsafe { f64::int_pow_fast_path($counter, 10) };
            add_temporary!(@mul $result, small_power as Limb, $value);
        }
    };

    // Add the maximum native value.
    (@max $format:ident, $result:ident, $counter:ident, $value:ident, $max:ident) => {
        add_temporary!(@mul $result, $max, $value);
        $counter = 0;
        $value = 0;
    };
}

/// Round-up a truncated value.
macro_rules! round_up_truncated {
    ($format:ident, $result:ident, $count:ident) => {{
        // Need to round-up.
        // Can't just add 1, since this can accidentally round-up
        // values to a halfway point, which can cause invalid results.
        add_temporary!(@mul $result, 10, 1);
        $count += 1;
    }};
}

/// Check and round-up the fraction if any non-zero digits exist.
macro_rules! round_up_nonzero {
    ($format:ident, $iter:expr, $result:ident, $count:ident) => {{
        for &digit in $iter {
            if digit != b'0' {
                round_up_truncated!($format, $result, $count);
                return ($result, $count);
            }
        }
    }};
}

/// Parse the full mantissa into a big integer.
///
/// Returns the parsed mantissa and the number of digits in the mantissa.
/// The max digits is the maximum number of digits plus one.
pub fn parse_mantissa<'a, Iter1, Iter2>(
    mut integer: Iter1,
    mut fraction: Iter2,
    max_digits: usize,
) -> (Bigint, usize)
where
    Iter1: Iterator<Item = &'a u8> + Clone,
    Iter2: Iterator<Item = &'a u8> + Clone,
{
    // Iteratively process all the data in the mantissa.
    // We do this via small, intermediate values which once we reach
    // the maximum number of digits we can process without overflow,
    // we add the temporary to the big integer.
    let mut counter: usize = 0;
    let mut count: usize = 0;
    let mut value: Limb = 0;
    let mut result = Bigint::new();

    // Now use our pre-computed small powers iteratively.
    // This is calculated as `⌊log(2^BITS - 1, 10)⌋`.
    let step: usize = if LIMB_BITS == 32 {
        9
    } else {
        19
    };
    let max_native = (10 as Limb).pow(step as u32);

    // Process the integer digits.
    'integer: loop {
        // Parse a digit at a time, until we reach step.
        while counter < step && count < max_digits {
            if let Some(&c) = integer.next() {
                add_digit!(c, value, counter, count);
            } else {
                break 'integer;
            }
        }

        // Check if we've exhausted our max digits.
        if count == max_digits {
            // Need to check if we're truncated, and round-up accordingly.
            // SAFETY: safe since `counter <= step`.
            add_temporary!(@end format, result, counter, value);
            round_up_nonzero!(format, integer, result, count);
            round_up_nonzero!(format, fraction, result, count);
            return (result, count);
        } else {
            // Add our temporary from the loop.
            // SAFETY: safe since `counter <= step`.
            add_temporary!(@max format, result, counter, value, max_native);
        }
    }

    // Skip leading fraction zeros.
    // Required to get an accurate count.
    if count == 0 {
        for &c in &mut fraction {
            if c != b'0' {
                add_digit!(c, value, counter, count);
                break;
            }
        }
    }

    // Process the fraction digits.
    'fraction: loop {
        // Parse a digit at a time, until we reach step.
        while counter < step && count < max_digits {
            if let Some(&c) = fraction.next() {
                add_digit!(c, value, counter, count);
            } else {
                break 'fraction;
            }
        }

        // Check if we've exhausted our max digits.
        if count == max_digits {
            // SAFETY: safe since `counter <= step`.
            add_temporary!(@end format, result, counter, value);
            round_up_nonzero!(format, fraction, result, count);
            return (result, count);
        } else {
            // Add our temporary from the loop.
            // SAFETY: safe since `counter <= step`.
            add_temporary!(@max format, result, counter, value, max_native);
        }
    }

    // We will always have a remainder, as long as we entered the loop
    // once, or counter % step is 0.
    // SAFETY: safe since `counter <= step`.
    add_temporary!(@end format, result, counter, value);

    (result, count)
}

// SCALING
// -------

/// Calculate the scientific exponent from a `Number` value.
/// Any other attempts would require slowdowns for faster algorithms.
#[inline]
pub fn scientific_exponent(num: &Number) -> i32 {
    // Use power reduction to make this faster.
    let mut mantissa = num.mantissa;
    let mut exponent = num.exponent;
    while mantissa >= 10000 {
        mantissa /= 10000;
        exponent += 4;
    }
    while mantissa >= 100 {
        mantissa /= 100;
        exponent += 2;
    }
    while mantissa >= 10 {
        mantissa /= 10;
        exponent += 1;
    }
    exponent as i32
}

/// Calculate `b` from a a representation of `b` as a float.
#[inline]
pub fn b<F: Float>(float: F) -> ExtendedFloat {
    ExtendedFloat {
        mant: float.mantissa(),
        exp: float.exponent(),
    }
}

/// Calculate `b+h` from a a representation of `b` as a float.
#[inline]
pub fn bh<F: Float>(float: F) -> ExtendedFloat {
    let fp = b(float);
    ExtendedFloat {
        mant: (fp.mant << 1) + 1,
        exp: fp.exp - 1,
    }
}