lexical_parse_float/
slow.rs

1//! Slow, fallback cases where we cannot unambiguously round a float.
2//!
3//! This occurs when we cannot determine the exact representation using
4//! both the fast path (native) cases nor the Lemire/Bellerophon algorithms,
5//! and therefore must fallback to a slow, arbitrary-precision representation.
6
7#![doc(hidden)]
8
9#[cfg(feature = "radix")]
10use crate::bigint::Bigfloat;
11use crate::bigint::{Bigint, Limb, LIMB_BITS};
12use crate::float::{extended_to_float, ExtendedFloat80, RawFloat};
13use crate::limits::{u32_power_limit, u64_power_limit};
14use crate::number::Number;
15use crate::shared;
16use core::cmp;
17#[cfg(not(feature = "compact"))]
18use lexical_parse_integer::algorithm;
19use lexical_util::digit::char_to_valid_digit_const;
20#[cfg(feature = "radix")]
21use lexical_util::digit::digit_to_char_const;
22use lexical_util::format::NumberFormat;
23use lexical_util::iterator::{AsBytes, BytesIter};
24use lexical_util::num::{AsPrimitive, Integer};
25
26// ALGORITHM
27// ---------
28
29/// Parse the significant digits and biased, binary exponent of a float.
30///
31/// This is a fallback algorithm that uses a big-integer representation
32/// of the float, and therefore is considerably slower than faster
33/// approximations. However, it will always determine how to round
34/// the significant digits to the nearest machine float, allowing
35/// use to handle near half-way cases.
36///
37/// Near half-way cases are halfway between two consecutive machine floats.
38/// For example, the float `16777217.0` has a bitwise representation of
39/// `100000000000000000000000 1`. Rounding to a single-precision float,
40/// the trailing `1` is truncated. Using round-nearest, tie-even, any
41/// value above `16777217.0` must be rounded up to `16777218.0`, while
42/// any value before or equal to `16777217.0` must be rounded down
43/// to `16777216.0`. These near-halfway conversions therefore may require
44/// a large number of digits to unambiguously determine how to round.
45#[inline]
46pub fn slow_radix<F: RawFloat, const FORMAT: u128>(
47    num: Number,
48    fp: ExtendedFloat80,
49) -> ExtendedFloat80 {
50    // Ensure our preconditions are valid:
51    //  1. The significant digits are not shifted into place.
52    debug_assert!(fp.mant & (1 << 63) != 0);
53
54    let format = NumberFormat::<{ FORMAT }> {};
55
56    // This assumes the sign bit has already been parsed, and we're
57    // starting with the integer digits, and the float format has been
58    // correctly validated.
59    let sci_exp = scientific_exponent::<FORMAT>(&num);
60
61    // We have 3 major algorithms we use for this:
62    //  1. An algorithm with a finite number of digits and a positive exponent.
63    //  2. An algorithm with a finite number of digits and a negative exponent.
64    //  3. A fallback algorithm with a non-finite number of digits.
65
66    // In order for a float in radix `b` with a finite number of digits
67    // to have a finite representation in radix `y`, `b` should divide
68    // an integer power of `y`. This means for binary, all even radixes
69    // have finite representations, and all odd ones do not.
70    #[cfg(feature = "radix")]
71    {
72        if let Some(max_digits) = F::max_digits(format.radix()) {
73            // Can use our finite number of digit algorithm.
74            digit_comp::<F, FORMAT>(num, fp, sci_exp, max_digits)
75        } else {
76            // Fallback to infinite digits.
77            byte_comp::<F, FORMAT>(num, fp, sci_exp)
78        }
79    }
80
81    #[cfg(not(feature = "radix"))]
82    {
83        // Can use our finite number of digit algorithm.
84        let max_digits = F::max_digits(format.radix()).unwrap();
85        digit_comp::<F, FORMAT>(num, fp, sci_exp, max_digits)
86    }
87}
88
89/// Algorithm that generates the mantissa for a finite representation.
90///
91/// For a positive exponent relative to the significant digits, this
92/// is just a multiplication by an exponent power. For a negative
93/// exponent relative to the significant digits, we scale the real
94/// digits to the theoretical digits for `b` and determine if we
95/// need to round-up.
96#[inline]
97pub fn digit_comp<F: RawFloat, const FORMAT: u128>(
98    num: Number,
99    fp: ExtendedFloat80,
100    sci_exp: i32,
101    max_digits: usize,
102) -> ExtendedFloat80 {
103    let (bigmant, digits) = parse_mantissa::<FORMAT>(num, max_digits);
104    // This can't underflow, since `digits` is at most `max_digits`.
105    let exponent = sci_exp + 1 - digits as i32;
106    if exponent >= 0 {
107        positive_digit_comp::<F, FORMAT>(bigmant, exponent)
108    } else {
109        negative_digit_comp::<F, FORMAT>(bigmant, fp, exponent)
110    }
111}
112
113/// Generate the significant digits with a positive exponent relative to mantissa.
114pub fn positive_digit_comp<F: RawFloat, const FORMAT: u128>(
115    mut bigmant: Bigint,
116    exponent: i32,
117) -> ExtendedFloat80 {
118    let format = NumberFormat::<{ FORMAT }> {};
119
120    // Simple, we just need to multiply by the power of the radix.
121    // Now, we can calculate the mantissa and the exponent from this.
122    // The binary exponent is the binary exponent for the mantissa
123    // shifted to the hidden bit.
124    bigmant.pow(format.radix(), exponent as u32).unwrap();
125
126    // Get the exact representation of the float from the big integer.
127    // hi64 checks **all** the remaining bits after the mantissa,
128    // so it will check if **any** truncated digits exist.
129    let (mant, is_truncated) = bigmant.hi64();
130    let exp = bigmant.bit_length() as i32 - 64 + F::EXPONENT_BIAS;
131    let mut fp = ExtendedFloat80 {
132        mant,
133        exp,
134    };
135
136    // Shift the digits into position and determine if we need to round-up.
137    shared::round::<F, _>(&mut fp, |f, s| {
138        shared::round_nearest_tie_even(f, s, |is_odd, is_halfway, is_above| {
139            is_above || (is_halfway && is_truncated) || (is_odd && is_halfway)
140        });
141    });
142    fp
143}
144
145/// Generate the significant digits with a negative exponent relative to mantissa.
146///
147/// This algorithm is quite simple: we have the significant digits `m1 * b^N1`,
148/// where `m1` is the bigint mantissa, `b` is the radix, and `N1` is the radix
149/// exponent. We then calculate the theoretical representation of `b+h`, which
150/// is `m2 * 2^N2`, where `m2` is the bigint mantissa and `N2` is the binary
151/// exponent. If we had infinite, efficient floating precision, this would be
152/// equal to `m1 / b^-N1` and then compare it to `m2 * 2^N2`.
153///
154/// Since we cannot divide and keep precision, we must multiply the other:
155/// if we want to do `m1 / b^-N1 >= m2 * 2^N2`, we can do
156/// `m1 >= m2 * b^-N1 * 2^N2` Going to the decimal case, we can show and example
157/// and simplify this further: `m1 >= m2 * 2^N2 * 10^-N1`. Since we can remove
158/// a power-of-two, this is `m1 >= m2 * 2^(N2 - N1) * 5^-N1`. Therefore, if
159/// `N2 - N1 > 0`, we need have `m1 >= m2 * 2^(N2 - N1) * 5^-N1`, otherwise,
160/// we have `m1 * 2^(N1 - N2) >= m2 * 5^-N1`, where the resulting exponents
161/// are all positive.
162///
163/// This allows us to compare both floats using integers efficiently
164/// without any loss of precision.
165#[allow(clippy::comparison_chain)]
166pub fn negative_digit_comp<F: RawFloat, const FORMAT: u128>(
167    bigmant: Bigint,
168    mut fp: ExtendedFloat80,
169    exponent: i32,
170) -> ExtendedFloat80 {
171    // Ensure our preconditions are valid:
172    //  1. The significant digits are not shifted into place.
173    debug_assert!(fp.mant & (1 << 63) != 0);
174
175    let format = NumberFormat::<FORMAT> {};
176    let radix = format.radix();
177
178    // Get the significant digits and radix exponent for the real digits.
179    let mut real_digits = bigmant;
180    let real_exp = exponent;
181    debug_assert!(real_exp < 0);
182
183    // Round down our extended-precision float and calculate `b`.
184    let mut b = fp;
185    shared::round::<F, _>(&mut b, shared::round_down);
186    let b = extended_to_float::<F>(b);
187
188    // Get the significant digits and the binary exponent for `b+h`.
189    let theor = bh(b);
190    let mut theor_digits = Bigint::from_u64(theor.mant);
191    let theor_exp = theor.exp;
192
193    // We need to scale the real digits and `b+h` digits to be the same
194    // order. We currently have `real_exp`, in `radix`, that needs to be
195    // shifted to `theor_digits` (since it is negative), and `theor_exp`
196    // to either `theor_digits` or `real_digits` as a power of 2 (since it
197    // may be positive or negative). Try to remove as many powers of 2
198    // as possible. All values are relative to `theor_digits`, that is,
199    // reflect the power you need to multiply `theor_digits` by.
200    let (binary_exp, halfradix_exp, radix_exp) = match radix.is_even() {
201        // Can remove a power-of-two.
202        // Both are on opposite-sides of equation, can factor out a
203        // power of two.
204        //
205        // Example: 10^-10, 2^-10   -> ( 0, 10, 0)
206        // Example: 10^-10, 2^-15   -> (-5, 10, 0)
207        // Example: 10^-10, 2^-5    -> ( 5, 10, 0)
208        // Example: 10^-10, 2^5     -> (15, 10, 0)
209        true => (theor_exp - real_exp, -real_exp, 0),
210        // Cannot remove a power-of-two.
211        false => (theor_exp, 0, -real_exp),
212    };
213
214    if halfradix_exp != 0 {
215        theor_digits.pow(radix / 2, halfradix_exp as u32).unwrap();
216    }
217    if radix_exp != 0 {
218        theor_digits.pow(radix, radix_exp as u32).unwrap();
219    }
220    if binary_exp > 0 {
221        theor_digits.pow(2, binary_exp as u32).unwrap();
222    } else if binary_exp < 0 {
223        real_digits.pow(2, (-binary_exp) as u32).unwrap();
224    }
225
226    // Compare our theoretical and real digits and round nearest, tie even.
227    let ord = real_digits.data.cmp(&theor_digits.data);
228    shared::round::<F, _>(&mut fp, |f, s| {
229        shared::round_nearest_tie_even(f, s, |is_odd, _, _| {
230            // Can ignore `is_halfway` and `is_above`, since those were
231            // calculates using less significant digits.
232            match ord {
233                cmp::Ordering::Greater => true,
234                cmp::Ordering::Less => false,
235                cmp::Ordering::Equal if is_odd => true,
236                cmp::Ordering::Equal => false,
237            }
238        });
239    });
240    fp
241}
242
243/// Try to parse 8 digits at a time.
244#[cfg(not(feature = "compact"))]
245macro_rules! try_parse_8digits {
246    (
247        $format:ident,
248        $iter:ident,
249        $value:ident,
250        $count:ident,
251        $counter:ident,
252        $step:ident,
253        $max_digits:ident
254    ) => {{
255        let format = NumberFormat::<$format> {};
256        let radix = format.radix() as Limb;
257
258        // Try 8-digit optimizations.
259        if can_try_parse_8digits!($iter, radix) {
260            let radix2 = radix.wrapping_mul(radix);
261            let radix4 = radix2.wrapping_mul(radix2);
262            let radix8 = radix4.wrapping_mul(radix4);
263
264            while $step - $counter >= 8 && $max_digits - $count >= 8 {
265                if let Some(v) = algorithm::try_parse_8digits::<Limb, _, FORMAT>(&mut $iter) {
266                    $value = $value.wrapping_mul(radix8).wrapping_add(v);
267                    $counter += 8;
268                    $count += 8;
269                } else {
270                    break;
271                }
272            }
273        }
274    }};
275}
276
277/// Add a digit to the temporary value.
278macro_rules! add_digit {
279    ($c:ident, $radix:ident, $value:ident, $counter:ident, $count:ident) => {{
280        let digit = char_to_valid_digit_const($c, $radix);
281        $value *= $radix as Limb;
282        $value += digit as Limb;
283
284        // Increment our counters.
285        $counter += 1;
286        $count += 1;
287    }};
288}
289
290/// Add a temporary value to our mantissa.
291macro_rules! add_temporary {
292    // Multiply by the small power and add the native value.
293    (@mul $result:ident, $power:expr, $value:expr) => {
294        $result.data.mul_small($power).unwrap();
295        $result.data.add_small($value).unwrap();
296    };
297
298    // Add a temporary where we won't read the counter results internally.
299    //
300    // # Safety
301    //
302    // Safe is `counter <= step`, or smaller than the table size.
303    (@end $format:ident, $result:ident, $counter:ident, $value:ident) => {
304        if $counter != 0 {
305            // SAFETY: safe, since `counter <= step`, or smaller than the table size.
306            let small_power = unsafe { f64::int_pow_fast_path($counter, $format.radix()) };
307            add_temporary!(@mul $result, small_power as Limb, $value);
308        }
309    };
310
311    // Add the maximum native value.
312    (@max $format:ident, $result:ident, $counter:ident, $value:ident, $max:ident) => {
313        add_temporary!(@mul $result, $max, $value);
314        $counter = 0;
315        $value = 0;
316    };
317}
318
319/// Round-up a truncated value.
320macro_rules! round_up_truncated {
321    ($format:ident, $result:ident, $count:ident) => {{
322        // Need to round-up.
323        // Can't just add 1, since this can accidentally round-up
324        // values to a halfway point, which can cause invalid results.
325        add_temporary!(@mul $result, $format.radix() as Limb, 1);
326        $count += 1;
327    }};
328}
329
330/// Check and round-up the fraction if any non-zero digits exist.
331macro_rules! round_up_nonzero {
332    ($format:ident, $iter:expr, $result:ident, $count:ident) => {{
333        // NOTE: All digits must be valid.
334        let mut iter = $iter;
335
336        // First try reading 8-digits at a time.
337        if iter.is_contiguous() {
338            while let Some(value) = iter.read::<u64>() {
339                // SAFETY: safe since we have at least 8 bytes in the buffer.
340                unsafe { iter.step_by_unchecked(8) };
341                if value != 0x3030_3030_3030_3030 {
342                    // Have non-zero digits, exit early.
343                    round_up_truncated!($format, $result, $count);
344                    return ($result, $count);
345                }
346            }
347        }
348
349        for &digit in iter {
350            if digit != b'0' {
351                round_up_truncated!($format, $result, $count);
352                return ($result, $count);
353            }
354        }
355    }};
356}
357
358/// Parse the full mantissa into a big integer.
359///
360/// Returns the parsed mantissa and the number of digits in the mantissa.
361/// The max digits is the maximum number of digits plus one.
362pub fn parse_mantissa<const FORMAT: u128>(num: Number, max_digits: usize) -> (Bigint, usize) {
363    let format = NumberFormat::<FORMAT> {};
364    let radix = format.radix();
365
366    // Iteratively process all the data in the mantissa.
367    // We do this via small, intermediate values which once we reach
368    // the maximum number of digits we can process without overflow,
369    // we add the temporary to the big integer.
370    let mut counter: usize = 0;
371    let mut count: usize = 0;
372    let mut value: Limb = 0;
373    let mut result = Bigint::new();
374
375    // Now use our pre-computed small powers iteratively.
376    let step = if LIMB_BITS == 32 {
377        u32_power_limit(format.radix())
378    } else {
379        u64_power_limit(format.radix())
380    } as usize;
381    let max_native = (format.radix() as Limb).pow(step as u32);
382
383    // Process the integer digits.
384    let mut integer = num.integer.bytes::<FORMAT>();
385    let mut integer_iter = integer.integer_iter();
386    integer_iter.skip_zeros();
387    'integer: loop {
388        #[cfg(not(feature = "compact"))]
389        try_parse_8digits!(FORMAT, integer_iter, value, count, counter, step, max_digits);
390
391        // Parse a digit at a time, until we reach step.
392        while counter < step && count < max_digits {
393            if let Some(&c) = integer_iter.next() {
394                add_digit!(c, radix, value, counter, count);
395            } else {
396                break 'integer;
397            }
398        }
399
400        // Check if we've exhausted our max digits.
401        if count == max_digits {
402            // Need to check if we're truncated, and round-up accordingly.
403            // SAFETY: safe since `counter <= step`.
404            add_temporary!(@end format, result, counter, value);
405            round_up_nonzero!(format, integer_iter, result, count);
406            if let Some(fraction) = num.fraction {
407                let mut fraction = fraction.bytes::<FORMAT>();
408                round_up_nonzero!(format, fraction.fraction_iter(), result, count)
409            }
410            return (result, count);
411        } else {
412            // Add our temporary from the loop.
413            // SAFETY: safe since `counter <= step`.
414            add_temporary!(@max format, result, counter, value, max_native);
415        }
416    }
417
418    // Process the fraction digits.
419    if let Some(fraction) = num.fraction {
420        let mut fraction = fraction.bytes::<FORMAT>();
421        let mut fraction_iter = fraction.integer_iter();
422        if count == 0 {
423            // No digits added yet, can skip leading fraction zeros too.
424            fraction_iter.skip_zeros();
425        }
426        'fraction: loop {
427            #[cfg(not(feature = "compact"))]
428            try_parse_8digits!(FORMAT, fraction_iter, value, count, counter, step, max_digits);
429
430            // Parse a digit at a time, until we reach step.
431            while counter < step && count < max_digits {
432                if let Some(&c) = fraction_iter.next() {
433                    add_digit!(c, radix, value, counter, count);
434                } else {
435                    break 'fraction;
436                }
437            }
438
439            // Check if we've exhausted our max digits.
440            if count == max_digits {
441                // SAFETY: safe since `counter <= step`.
442                add_temporary!(@end format, result, counter, value);
443                round_up_nonzero!(format, fraction_iter, result, count);
444                return (result, count);
445            } else {
446                // Add our temporary from the loop.
447                // SAFETY: safe since `counter <= step`.
448                add_temporary!(@max format, result, counter, value, max_native);
449            }
450        }
451    }
452
453    // We will always have a remainder, as long as we entered the loop
454    // once, or counter % step is 0.
455    // SAFETY: safe since `counter <= step`.
456    add_temporary!(@end format, result, counter, value);
457
458    (result, count)
459}
460
461/// Compare actual integer digits to the theoretical digits.
462#[cfg(feature = "radix")]
463macro_rules! integer_compare {
464    ($iter:ident, $num:ident, $den:ident, $radix:ident) => {{
465        // Compare the integer digits.
466        while !$num.data.is_empty() {
467            // All digits **must** be valid.
468            let actual = match $iter.next() {
469                Some(&v) => v,
470                // Could have hit the decimal point.
471                _ => break,
472            };
473            let rem = $num.data.quorem(&$den.data) as u32;
474            let expected = digit_to_char_const(rem, $radix);
475            $num.data.mul_small($radix as Limb).unwrap();
476            if actual < expected {
477                return cmp::Ordering::Less;
478            } else if actual > expected {
479                return cmp::Ordering::Greater;
480            }
481        }
482
483        // Still have integer digits, check if any are non-zero.
484        if $num.data.is_empty() {
485            for &digit in $iter {
486                if digit != b'0' {
487                    return cmp::Ordering::Greater;
488                }
489            }
490        }
491    }};
492}
493
494/// Compare actual fraction digits to the theoretical digits.
495#[cfg(feature = "radix")]
496macro_rules! fraction_compare {
497    ($iter:ident, $num:ident, $den:ident, $radix:ident) => {{
498        // Compare the fraction digits.
499        // We can only be here if we hit a decimal point.
500        while !$num.data.is_empty() {
501            // All digits **must** be valid.
502            let actual = match $iter.next() {
503                Some(&v) => v,
504                // No more actual digits, or hit the exponent.
505                _ => return cmp::Ordering::Less,
506            };
507            let rem = $num.data.quorem(&$den.data) as u32;
508            let expected = digit_to_char_const(rem, $radix);
509            $num.data.mul_small($radix as Limb).unwrap();
510            if actual < expected {
511                return cmp::Ordering::Less;
512            } else if actual > expected {
513                return cmp::Ordering::Greater;
514            }
515        }
516
517        // Still have fraction digits, check if any are non-zero.
518        for &digit in $iter {
519            if digit != b'0' {
520                return cmp::Ordering::Greater;
521            }
522        }
523    }};
524}
525
526/// Compare theoretical digits to halfway point from theoretical digits.
527///
528/// Generates a float representing the halfway point, and generates
529/// theoretical digits as bytes, and compares the generated digits to
530/// the actual input.
531///
532/// Compares the known string to theoretical digits generated on the
533/// fly for `b+h`, where a string representation of a float is between
534/// `b` and `b+u`, where `b+u` is 1 unit in the least-precision. Therefore,
535/// the string must be close to `b+h`.
536///
537/// Adapted from "Bigcomp: Deciding Truncated, Near Halfway Conversions",
538/// available [here](https://www.exploringbinary.com/bigcomp-deciding-truncated-near-halfway-conversions/).
539#[cfg(feature = "radix")]
540#[allow(clippy::comparison_chain)]
541pub fn byte_comp<F: RawFloat, const FORMAT: u128>(
542    number: Number,
543    mut fp: ExtendedFloat80,
544    sci_exp: i32,
545) -> ExtendedFloat80 {
546    // Ensure our preconditions are valid:
547    //  1. The significant digits are not shifted into place.
548    debug_assert!(fp.mant & (1 << 63) != 0);
549
550    let format = NumberFormat::<FORMAT> {};
551
552    // Round down our extended-precision float and calculate `b`.
553    let mut b = fp;
554    shared::round::<F, _>(&mut b, shared::round_down);
555    let b = extended_to_float::<F>(b);
556
557    // Calculate `b+h` to create a ratio for our theoretical digits.
558    let theor = Bigfloat::from_float(bh::<F>(b));
559
560    // Now, create a scaling factor for the digit count.
561    let mut factor = Bigfloat::from_u32(1);
562    factor.pow(format.radix(), sci_exp.unsigned_abs()).unwrap();
563    let mut num: Bigfloat;
564    let mut den: Bigfloat;
565
566    if sci_exp < 0 {
567        // Need to have the basen factor be the numerator, and the fp
568        // be the denominator. Since we assumed that theor was the numerator,
569        // if it's the denominator, we need to multiply it into the numerator.
570        num = factor;
571        num.data *= &theor.data;
572        den = Bigfloat::from_u32(1);
573        den.exp = -theor.exp;
574    } else {
575        num = theor;
576        den = factor;
577    }
578
579    // Scale the denominator so it has the number of bits
580    // in the radix as the number of leading zeros.
581    let wlz = integral_binary_factor(format.radix());
582    let nlz = den.leading_zeros().wrapping_sub(wlz) & (32 - 1);
583    if nlz != 0 {
584        den.shl_bits(nlz as usize).unwrap();
585        den.exp -= nlz as i32;
586    }
587
588    // Need to scale the numerator or denominator to the same value.
589    // We don't want to shift the denominator, so...
590    let diff = den.exp - num.exp;
591    let shift = diff.unsigned_abs() as usize;
592    if diff < 0 {
593        // Need to shift the numerator left.
594        num.shl(shift).unwrap();
595        num.exp -= shift as i32;
596    } else if diff > 0 {
597        // Need to shift denominator left, go by a power of LIMB_BITS.
598        // After this, the numerator will be non-normalized, and the
599        // denominator will be normalized. We need to add one to the
600        // quotient,since we're calculating the ceiling of the divmod.
601        let (q, r) = shift.ceil_divmod(LIMB_BITS);
602        let r = -r;
603        if r != 0 {
604            num.shl_bits(r as usize).unwrap();
605            num.exp -= r;
606        }
607        if q != 0 {
608            den.shl_limbs(q).unwrap();
609            den.exp -= LIMB_BITS as i32 * q as i32;
610        }
611    }
612
613    // Compare our theoretical and real digits and round nearest, tie even.
614    let ord = compare_bytes::<FORMAT>(number, num, den);
615    shared::round::<F, _>(&mut fp, |f, s| {
616        shared::round_nearest_tie_even(f, s, |is_odd, _, _| {
617            // Can ignore `is_halfway` and `is_above`, since those were
618            // calculates using less significant digits.
619            match ord {
620                cmp::Ordering::Greater => true,
621                cmp::Ordering::Less => false,
622                cmp::Ordering::Equal if is_odd => true,
623                cmp::Ordering::Equal => false,
624            }
625        });
626    });
627    fp
628}
629
630/// Compare digits between the generated values the ratio and the actual view.
631#[cfg(feature = "radix")]
632pub fn compare_bytes<const FORMAT: u128>(
633    number: Number,
634    mut num: Bigfloat,
635    den: Bigfloat,
636) -> cmp::Ordering {
637    let format = NumberFormat::<FORMAT> {};
638    let radix = format.radix();
639
640    // Now need to compare the theoretical digits. First, I need to trim
641    // any leading zeros, and will also need to ignore trailing ones.
642    let mut integer = number.integer.bytes::<{ FORMAT }>();
643    let mut integer_iter = integer.integer_iter();
644    integer_iter.skip_zeros();
645    if integer_iter.is_done() {
646        // Cannot be empty, since we must have at least **some** significant digits.
647        let mut fraction = number.fraction.unwrap().bytes::<{ FORMAT }>();
648        let mut fraction_iter = fraction.fraction_iter();
649        fraction_iter.skip_zeros();
650        fraction_compare!(fraction_iter, num, den, radix);
651    } else {
652        integer_compare!(integer_iter, num, den, radix);
653        if let Some(fraction) = number.fraction {
654            let mut fraction = fraction.bytes::<{ FORMAT }>();
655            let mut fraction_iter = fraction.fraction_iter();
656            fraction_compare!(fraction_iter, num, den, radix);
657        } else if !num.data.is_empty() {
658            // We had more theoretical digits, but no more actual digits.
659            return cmp::Ordering::Less;
660        }
661    }
662
663    // Exhausted both, must be equal.
664    cmp::Ordering::Equal
665}
666
667// SCALING
668// -------
669
670/// Calculate the scientific exponent from a `Number` value.
671/// Any other attempts would require slowdowns for faster algorithms.
672#[inline]
673pub fn scientific_exponent<const FORMAT: u128>(num: &Number) -> i32 {
674    // This has the significant digits and exponent relative to those
675    // digits: therefore, we just need to scale to mantissa to `[1, radix)`.
676    // This doesn't need to be very fast.
677    let format = NumberFormat::<FORMAT> {};
678
679    // Use power reduction to make this faster: we need at least
680    // F::MANTISSA_SIZE bits, so we must have at least radix^4 digits.
681    // IF we're using base 3, we can have at most 11 divisions, and
682    // base 36, at most ~4. So, this is reasonably efficient.
683    let radix = format.radix() as u64;
684    let radix2 = radix * radix;
685    let radix4 = radix2 * radix2;
686    let mut mantissa = num.mantissa;
687    let mut exponent = num.exponent;
688    while mantissa >= radix4 {
689        mantissa /= radix4;
690        exponent += 4;
691    }
692    while mantissa >= radix2 {
693        mantissa /= radix2;
694        exponent += 2;
695    }
696    while mantissa >= radix {
697        mantissa /= radix;
698        exponent += 1;
699    }
700    exponent as i32
701}
702
703/// Calculate `b` from a a representation of `b` as a float.
704#[inline]
705pub fn b<F: RawFloat>(float: F) -> ExtendedFloat80 {
706    ExtendedFloat80 {
707        mant: float.mantissa().as_u64(),
708        exp: float.exponent(),
709    }
710}
711
712/// Calculate `b+h` from a a representation of `b` as a float.
713#[inline]
714pub fn bh<F: RawFloat>(float: F) -> ExtendedFloat80 {
715    let fp = b(float);
716    ExtendedFloat80 {
717        mant: (fp.mant << 1) + 1,
718        exp: fp.exp - 1,
719    }
720}
721
722/// Calculate the integral ceiling of the binary factor from a basen number.
723#[inline]
724pub const fn integral_binary_factor(radix: u32) -> u32 {
725    match radix {
726        3 if cfg!(feature = "radix") => 2,
727        5 if cfg!(feature = "radix") => 3,
728        6 if cfg!(feature = "radix") => 3,
729        7 if cfg!(feature = "radix") => 3,
730        9 if cfg!(feature = "radix") => 4,
731        10 => 4,
732        11 if cfg!(feature = "radix") => 4,
733        12 if cfg!(feature = "radix") => 4,
734        13 if cfg!(feature = "radix") => 4,
735        14 if cfg!(feature = "radix") => 4,
736        15 if cfg!(feature = "radix") => 4,
737        17 if cfg!(feature = "radix") => 5,
738        18 if cfg!(feature = "radix") => 5,
739        19 if cfg!(feature = "radix") => 5,
740        20 if cfg!(feature = "radix") => 5,
741        21 if cfg!(feature = "radix") => 5,
742        22 if cfg!(feature = "radix") => 5,
743        23 if cfg!(feature = "radix") => 5,
744        24 if cfg!(feature = "radix") => 5,
745        25 if cfg!(feature = "radix") => 5,
746        26 if cfg!(feature = "radix") => 5,
747        27 if cfg!(feature = "radix") => 5,
748        28 if cfg!(feature = "radix") => 5,
749        29 if cfg!(feature = "radix") => 5,
750        30 if cfg!(feature = "radix") => 5,
751        31 if cfg!(feature = "radix") => 5,
752        33 if cfg!(feature = "radix") => 6,
753        34 if cfg!(feature = "radix") => 6,
754        35 if cfg!(feature = "radix") => 6,
755        36 if cfg!(feature = "radix") => 6,
756        // Invalid radix
757        _ => 0,
758    }
759}