1cbd624adSopenharmony_ci//! Slow, fallback cases where we cannot unambiguously round a float. 2cbd624adSopenharmony_ci//! 3cbd624adSopenharmony_ci//! This occurs when we cannot determine the exact representation using 4cbd624adSopenharmony_ci//! both the fast path (native) cases nor the Lemire/Bellerophon algorithms, 5cbd624adSopenharmony_ci//! and therefore must fallback to a slow, arbitrary-precision representation. 6cbd624adSopenharmony_ci 7cbd624adSopenharmony_ci#![doc(hidden)] 8cbd624adSopenharmony_ci 9cbd624adSopenharmony_ciuse crate::bigint::{Bigint, Limb, LIMB_BITS}; 10cbd624adSopenharmony_ciuse crate::extended_float::{extended_to_float, ExtendedFloat}; 11cbd624adSopenharmony_ciuse crate::num::Float; 12cbd624adSopenharmony_ciuse crate::number::Number; 13cbd624adSopenharmony_ciuse crate::rounding::{round, round_down, round_nearest_tie_even}; 14cbd624adSopenharmony_ciuse core::cmp; 15cbd624adSopenharmony_ci 16cbd624adSopenharmony_ci// ALGORITHM 17cbd624adSopenharmony_ci// --------- 18cbd624adSopenharmony_ci 19cbd624adSopenharmony_ci/// Parse the significant digits and biased, binary exponent of a float. 20cbd624adSopenharmony_ci/// 21cbd624adSopenharmony_ci/// This is a fallback algorithm that uses a big-integer representation 22cbd624adSopenharmony_ci/// of the float, and therefore is considerably slower than faster 23cbd624adSopenharmony_ci/// approximations. However, it will always determine how to round 24cbd624adSopenharmony_ci/// the significant digits to the nearest machine float, allowing 25cbd624adSopenharmony_ci/// use to handle near half-way cases. 26cbd624adSopenharmony_ci/// 27cbd624adSopenharmony_ci/// Near half-way cases are halfway between two consecutive machine floats. 28cbd624adSopenharmony_ci/// For example, the float `16777217.0` has a bitwise representation of 29cbd624adSopenharmony_ci/// `100000000000000000000000 1`. Rounding to a single-precision float, 30cbd624adSopenharmony_ci/// the trailing `1` is truncated. Using round-nearest, tie-even, any 31cbd624adSopenharmony_ci/// value above `16777217.0` must be rounded up to `16777218.0`, while 32cbd624adSopenharmony_ci/// any value before or equal to `16777217.0` must be rounded down 33cbd624adSopenharmony_ci/// to `16777216.0`. These near-halfway conversions therefore may require 34cbd624adSopenharmony_ci/// a large number of digits to unambiguously determine how to round. 35cbd624adSopenharmony_ci#[inline] 36cbd624adSopenharmony_cipub fn slow<'a, F, Iter1, Iter2>( 37cbd624adSopenharmony_ci num: Number, 38cbd624adSopenharmony_ci fp: ExtendedFloat, 39cbd624adSopenharmony_ci integer: Iter1, 40cbd624adSopenharmony_ci fraction: Iter2, 41cbd624adSopenharmony_ci) -> ExtendedFloat 42cbd624adSopenharmony_ciwhere 43cbd624adSopenharmony_ci F: Float, 44cbd624adSopenharmony_ci Iter1: Iterator<Item = &'a u8> + Clone, 45cbd624adSopenharmony_ci Iter2: Iterator<Item = &'a u8> + Clone, 46cbd624adSopenharmony_ci{ 47cbd624adSopenharmony_ci // Ensure our preconditions are valid: 48cbd624adSopenharmony_ci // 1. The significant digits are not shifted into place. 49cbd624adSopenharmony_ci debug_assert!(fp.mant & (1 << 63) != 0); 50cbd624adSopenharmony_ci 51cbd624adSopenharmony_ci // This assumes the sign bit has already been parsed, and we're 52cbd624adSopenharmony_ci // starting with the integer digits, and the float format has been 53cbd624adSopenharmony_ci // correctly validated. 54cbd624adSopenharmony_ci let sci_exp = scientific_exponent(&num); 55cbd624adSopenharmony_ci 56cbd624adSopenharmony_ci // We have 2 major algorithms we use for this: 57cbd624adSopenharmony_ci // 1. An algorithm with a finite number of digits and a positive exponent. 58cbd624adSopenharmony_ci // 2. An algorithm with a finite number of digits and a negative exponent. 59cbd624adSopenharmony_ci let (bigmant, digits) = parse_mantissa(integer, fraction, F::MAX_DIGITS); 60cbd624adSopenharmony_ci let exponent = sci_exp + 1 - digits as i32; 61cbd624adSopenharmony_ci if exponent >= 0 { 62cbd624adSopenharmony_ci positive_digit_comp::<F>(bigmant, exponent) 63cbd624adSopenharmony_ci } else { 64cbd624adSopenharmony_ci negative_digit_comp::<F>(bigmant, fp, exponent) 65cbd624adSopenharmony_ci } 66cbd624adSopenharmony_ci} 67cbd624adSopenharmony_ci 68cbd624adSopenharmony_ci/// Generate the significant digits with a positive exponent relative to mantissa. 69cbd624adSopenharmony_cipub fn positive_digit_comp<F: Float>(mut bigmant: Bigint, exponent: i32) -> ExtendedFloat { 70cbd624adSopenharmony_ci // Simple, we just need to multiply by the power of the radix. 71cbd624adSopenharmony_ci // Now, we can calculate the mantissa and the exponent from this. 72cbd624adSopenharmony_ci // The binary exponent is the binary exponent for the mantissa 73cbd624adSopenharmony_ci // shifted to the hidden bit. 74cbd624adSopenharmony_ci bigmant.pow(10, exponent as u32).unwrap(); 75cbd624adSopenharmony_ci 76cbd624adSopenharmony_ci // Get the exact representation of the float from the big integer. 77cbd624adSopenharmony_ci // hi64 checks **all** the remaining bits after the mantissa, 78cbd624adSopenharmony_ci // so it will check if **any** truncated digits exist. 79cbd624adSopenharmony_ci let (mant, is_truncated) = bigmant.hi64(); 80cbd624adSopenharmony_ci let exp = bigmant.bit_length() as i32 - 64 + F::EXPONENT_BIAS; 81cbd624adSopenharmony_ci let mut fp = ExtendedFloat { 82cbd624adSopenharmony_ci mant, 83cbd624adSopenharmony_ci exp, 84cbd624adSopenharmony_ci }; 85cbd624adSopenharmony_ci 86cbd624adSopenharmony_ci // Shift the digits into position and determine if we need to round-up. 87cbd624adSopenharmony_ci round::<F, _>(&mut fp, |f, s| { 88cbd624adSopenharmony_ci round_nearest_tie_even(f, s, |is_odd, is_halfway, is_above| { 89cbd624adSopenharmony_ci is_above || (is_halfway && is_truncated) || (is_odd && is_halfway) 90cbd624adSopenharmony_ci }); 91cbd624adSopenharmony_ci }); 92cbd624adSopenharmony_ci fp 93cbd624adSopenharmony_ci} 94cbd624adSopenharmony_ci 95cbd624adSopenharmony_ci/// Generate the significant digits with a negative exponent relative to mantissa. 96cbd624adSopenharmony_ci/// 97cbd624adSopenharmony_ci/// This algorithm is quite simple: we have the significant digits `m1 * b^N1`, 98cbd624adSopenharmony_ci/// where `m1` is the bigint mantissa, `b` is the radix, and `N1` is the radix 99cbd624adSopenharmony_ci/// exponent. We then calculate the theoretical representation of `b+h`, which 100cbd624adSopenharmony_ci/// is `m2 * 2^N2`, where `m2` is the bigint mantissa and `N2` is the binary 101cbd624adSopenharmony_ci/// exponent. If we had infinite, efficient floating precision, this would be 102cbd624adSopenharmony_ci/// equal to `m1 / b^-N1` and then compare it to `m2 * 2^N2`. 103cbd624adSopenharmony_ci/// 104cbd624adSopenharmony_ci/// Since we cannot divide and keep precision, we must multiply the other: 105cbd624adSopenharmony_ci/// if we want to do `m1 / b^-N1 >= m2 * 2^N2`, we can do 106cbd624adSopenharmony_ci/// `m1 >= m2 * b^-N1 * 2^N2` Going to the decimal case, we can show and example 107cbd624adSopenharmony_ci/// and simplify this further: `m1 >= m2 * 2^N2 * 10^-N1`. Since we can remove 108cbd624adSopenharmony_ci/// a power-of-two, this is `m1 >= m2 * 2^(N2 - N1) * 5^-N1`. Therefore, if 109cbd624adSopenharmony_ci/// `N2 - N1 > 0`, we need have `m1 >= m2 * 2^(N2 - N1) * 5^-N1`, otherwise, 110cbd624adSopenharmony_ci/// we have `m1 * 2^(N1 - N2) >= m2 * 5^-N1`, where the resulting exponents 111cbd624adSopenharmony_ci/// are all positive. 112cbd624adSopenharmony_ci/// 113cbd624adSopenharmony_ci/// This allows us to compare both floats using integers efficiently 114cbd624adSopenharmony_ci/// without any loss of precision. 115cbd624adSopenharmony_ci#[allow(clippy::comparison_chain)] 116cbd624adSopenharmony_cipub fn negative_digit_comp<F: Float>( 117cbd624adSopenharmony_ci bigmant: Bigint, 118cbd624adSopenharmony_ci mut fp: ExtendedFloat, 119cbd624adSopenharmony_ci exponent: i32, 120cbd624adSopenharmony_ci) -> ExtendedFloat { 121cbd624adSopenharmony_ci // Ensure our preconditions are valid: 122cbd624adSopenharmony_ci // 1. The significant digits are not shifted into place. 123cbd624adSopenharmony_ci debug_assert!(fp.mant & (1 << 63) != 0); 124cbd624adSopenharmony_ci 125cbd624adSopenharmony_ci // Get the significant digits and radix exponent for the real digits. 126cbd624adSopenharmony_ci let mut real_digits = bigmant; 127cbd624adSopenharmony_ci let real_exp = exponent; 128cbd624adSopenharmony_ci debug_assert!(real_exp < 0); 129cbd624adSopenharmony_ci 130cbd624adSopenharmony_ci // Round down our extended-precision float and calculate `b`. 131cbd624adSopenharmony_ci let mut b = fp; 132cbd624adSopenharmony_ci round::<F, _>(&mut b, round_down); 133cbd624adSopenharmony_ci let b = extended_to_float::<F>(b); 134cbd624adSopenharmony_ci 135cbd624adSopenharmony_ci // Get the significant digits and the binary exponent for `b+h`. 136cbd624adSopenharmony_ci let theor = bh(b); 137cbd624adSopenharmony_ci let mut theor_digits = Bigint::from_u64(theor.mant); 138cbd624adSopenharmony_ci let theor_exp = theor.exp; 139cbd624adSopenharmony_ci 140cbd624adSopenharmony_ci // We need to scale the real digits and `b+h` digits to be the same 141cbd624adSopenharmony_ci // order. We currently have `real_exp`, in `radix`, that needs to be 142cbd624adSopenharmony_ci // shifted to `theor_digits` (since it is negative), and `theor_exp` 143cbd624adSopenharmony_ci // to either `theor_digits` or `real_digits` as a power of 2 (since it 144cbd624adSopenharmony_ci // may be positive or negative). Try to remove as many powers of 2 145cbd624adSopenharmony_ci // as possible. All values are relative to `theor_digits`, that is, 146cbd624adSopenharmony_ci // reflect the power you need to multiply `theor_digits` by. 147cbd624adSopenharmony_ci // 148cbd624adSopenharmony_ci // Both are on opposite-sides of equation, can factor out a 149cbd624adSopenharmony_ci // power of two. 150cbd624adSopenharmony_ci // 151cbd624adSopenharmony_ci // Example: 10^-10, 2^-10 -> ( 0, 10, 0) 152cbd624adSopenharmony_ci // Example: 10^-10, 2^-15 -> (-5, 10, 0) 153cbd624adSopenharmony_ci // Example: 10^-10, 2^-5 -> ( 5, 10, 0) 154cbd624adSopenharmony_ci // Example: 10^-10, 2^5 -> (15, 10, 0) 155cbd624adSopenharmony_ci let binary_exp = theor_exp - real_exp; 156cbd624adSopenharmony_ci let halfradix_exp = -real_exp; 157cbd624adSopenharmony_ci if halfradix_exp != 0 { 158cbd624adSopenharmony_ci theor_digits.pow(5, halfradix_exp as u32).unwrap(); 159cbd624adSopenharmony_ci } 160cbd624adSopenharmony_ci if binary_exp > 0 { 161cbd624adSopenharmony_ci theor_digits.pow(2, binary_exp as u32).unwrap(); 162cbd624adSopenharmony_ci } else if binary_exp < 0 { 163cbd624adSopenharmony_ci real_digits.pow(2, (-binary_exp) as u32).unwrap(); 164cbd624adSopenharmony_ci } 165cbd624adSopenharmony_ci 166cbd624adSopenharmony_ci // Compare our theoretical and real digits and round nearest, tie even. 167cbd624adSopenharmony_ci let ord = real_digits.data.cmp(&theor_digits.data); 168cbd624adSopenharmony_ci round::<F, _>(&mut fp, |f, s| { 169cbd624adSopenharmony_ci round_nearest_tie_even(f, s, |is_odd, _, _| { 170cbd624adSopenharmony_ci // Can ignore `is_halfway` and `is_above`, since those were 171cbd624adSopenharmony_ci // calculates using less significant digits. 172cbd624adSopenharmony_ci match ord { 173cbd624adSopenharmony_ci cmp::Ordering::Greater => true, 174cbd624adSopenharmony_ci cmp::Ordering::Less => false, 175cbd624adSopenharmony_ci cmp::Ordering::Equal if is_odd => true, 176cbd624adSopenharmony_ci cmp::Ordering::Equal => false, 177cbd624adSopenharmony_ci } 178cbd624adSopenharmony_ci }); 179cbd624adSopenharmony_ci }); 180cbd624adSopenharmony_ci fp 181cbd624adSopenharmony_ci} 182cbd624adSopenharmony_ci 183cbd624adSopenharmony_ci/// Add a digit to the temporary value. 184cbd624adSopenharmony_cimacro_rules! add_digit { 185cbd624adSopenharmony_ci ($c:ident, $value:ident, $counter:ident, $count:ident) => {{ 186cbd624adSopenharmony_ci let digit = $c - b'0'; 187cbd624adSopenharmony_ci $value *= 10 as Limb; 188cbd624adSopenharmony_ci $value += digit as Limb; 189cbd624adSopenharmony_ci 190cbd624adSopenharmony_ci // Increment our counters. 191cbd624adSopenharmony_ci $counter += 1; 192cbd624adSopenharmony_ci $count += 1; 193cbd624adSopenharmony_ci }}; 194cbd624adSopenharmony_ci} 195cbd624adSopenharmony_ci 196cbd624adSopenharmony_ci/// Add a temporary value to our mantissa. 197cbd624adSopenharmony_cimacro_rules! add_temporary { 198cbd624adSopenharmony_ci // Multiply by the small power and add the native value. 199cbd624adSopenharmony_ci (@mul $result:ident, $power:expr, $value:expr) => { 200cbd624adSopenharmony_ci $result.data.mul_small($power).unwrap(); 201cbd624adSopenharmony_ci $result.data.add_small($value).unwrap(); 202cbd624adSopenharmony_ci }; 203cbd624adSopenharmony_ci 204cbd624adSopenharmony_ci // # Safety 205cbd624adSopenharmony_ci // 206cbd624adSopenharmony_ci // Safe is `counter <= step`, or smaller than the table size. 207cbd624adSopenharmony_ci ($format:ident, $result:ident, $counter:ident, $value:ident) => { 208cbd624adSopenharmony_ci if $counter != 0 { 209cbd624adSopenharmony_ci // SAFETY: safe, since `counter <= step`, or smaller than the table size. 210cbd624adSopenharmony_ci let small_power = unsafe { f64::int_pow_fast_path($counter, 10) }; 211cbd624adSopenharmony_ci add_temporary!(@mul $result, small_power as Limb, $value); 212cbd624adSopenharmony_ci $counter = 0; 213cbd624adSopenharmony_ci $value = 0; 214cbd624adSopenharmony_ci } 215cbd624adSopenharmony_ci }; 216cbd624adSopenharmony_ci 217cbd624adSopenharmony_ci // Add a temporary where we won't read the counter results internally. 218cbd624adSopenharmony_ci // 219cbd624adSopenharmony_ci // # Safety 220cbd624adSopenharmony_ci // 221cbd624adSopenharmony_ci // Safe is `counter <= step`, or smaller than the table size. 222cbd624adSopenharmony_ci (@end $format:ident, $result:ident, $counter:ident, $value:ident) => { 223cbd624adSopenharmony_ci if $counter != 0 { 224cbd624adSopenharmony_ci // SAFETY: safe, since `counter <= step`, or smaller than the table size. 225cbd624adSopenharmony_ci let small_power = unsafe { f64::int_pow_fast_path($counter, 10) }; 226cbd624adSopenharmony_ci add_temporary!(@mul $result, small_power as Limb, $value); 227cbd624adSopenharmony_ci } 228cbd624adSopenharmony_ci }; 229cbd624adSopenharmony_ci 230cbd624adSopenharmony_ci // Add the maximum native value. 231cbd624adSopenharmony_ci (@max $format:ident, $result:ident, $counter:ident, $value:ident, $max:ident) => { 232cbd624adSopenharmony_ci add_temporary!(@mul $result, $max, $value); 233cbd624adSopenharmony_ci $counter = 0; 234cbd624adSopenharmony_ci $value = 0; 235cbd624adSopenharmony_ci }; 236cbd624adSopenharmony_ci} 237cbd624adSopenharmony_ci 238cbd624adSopenharmony_ci/// Round-up a truncated value. 239cbd624adSopenharmony_cimacro_rules! round_up_truncated { 240cbd624adSopenharmony_ci ($format:ident, $result:ident, $count:ident) => {{ 241cbd624adSopenharmony_ci // Need to round-up. 242cbd624adSopenharmony_ci // Can't just add 1, since this can accidentally round-up 243cbd624adSopenharmony_ci // values to a halfway point, which can cause invalid results. 244cbd624adSopenharmony_ci add_temporary!(@mul $result, 10, 1); 245cbd624adSopenharmony_ci $count += 1; 246cbd624adSopenharmony_ci }}; 247cbd624adSopenharmony_ci} 248cbd624adSopenharmony_ci 249cbd624adSopenharmony_ci/// Check and round-up the fraction if any non-zero digits exist. 250cbd624adSopenharmony_cimacro_rules! round_up_nonzero { 251cbd624adSopenharmony_ci ($format:ident, $iter:expr, $result:ident, $count:ident) => {{ 252cbd624adSopenharmony_ci for &digit in $iter { 253cbd624adSopenharmony_ci if digit != b'0' { 254cbd624adSopenharmony_ci round_up_truncated!($format, $result, $count); 255cbd624adSopenharmony_ci return ($result, $count); 256cbd624adSopenharmony_ci } 257cbd624adSopenharmony_ci } 258cbd624adSopenharmony_ci }}; 259cbd624adSopenharmony_ci} 260cbd624adSopenharmony_ci 261cbd624adSopenharmony_ci/// Parse the full mantissa into a big integer. 262cbd624adSopenharmony_ci/// 263cbd624adSopenharmony_ci/// Returns the parsed mantissa and the number of digits in the mantissa. 264cbd624adSopenharmony_ci/// The max digits is the maximum number of digits plus one. 265cbd624adSopenharmony_cipub fn parse_mantissa<'a, Iter1, Iter2>( 266cbd624adSopenharmony_ci mut integer: Iter1, 267cbd624adSopenharmony_ci mut fraction: Iter2, 268cbd624adSopenharmony_ci max_digits: usize, 269cbd624adSopenharmony_ci) -> (Bigint, usize) 270cbd624adSopenharmony_ciwhere 271cbd624adSopenharmony_ci Iter1: Iterator<Item = &'a u8> + Clone, 272cbd624adSopenharmony_ci Iter2: Iterator<Item = &'a u8> + Clone, 273cbd624adSopenharmony_ci{ 274cbd624adSopenharmony_ci // Iteratively process all the data in the mantissa. 275cbd624adSopenharmony_ci // We do this via small, intermediate values which once we reach 276cbd624adSopenharmony_ci // the maximum number of digits we can process without overflow, 277cbd624adSopenharmony_ci // we add the temporary to the big integer. 278cbd624adSopenharmony_ci let mut counter: usize = 0; 279cbd624adSopenharmony_ci let mut count: usize = 0; 280cbd624adSopenharmony_ci let mut value: Limb = 0; 281cbd624adSopenharmony_ci let mut result = Bigint::new(); 282cbd624adSopenharmony_ci 283cbd624adSopenharmony_ci // Now use our pre-computed small powers iteratively. 284cbd624adSopenharmony_ci // This is calculated as `⌊log(2^BITS - 1, 10)⌋`. 285cbd624adSopenharmony_ci let step: usize = if LIMB_BITS == 32 { 286cbd624adSopenharmony_ci 9 287cbd624adSopenharmony_ci } else { 288cbd624adSopenharmony_ci 19 289cbd624adSopenharmony_ci }; 290cbd624adSopenharmony_ci let max_native = (10 as Limb).pow(step as u32); 291cbd624adSopenharmony_ci 292cbd624adSopenharmony_ci // Process the integer digits. 293cbd624adSopenharmony_ci 'integer: loop { 294cbd624adSopenharmony_ci // Parse a digit at a time, until we reach step. 295cbd624adSopenharmony_ci while counter < step && count < max_digits { 296cbd624adSopenharmony_ci if let Some(&c) = integer.next() { 297cbd624adSopenharmony_ci add_digit!(c, value, counter, count); 298cbd624adSopenharmony_ci } else { 299cbd624adSopenharmony_ci break 'integer; 300cbd624adSopenharmony_ci } 301cbd624adSopenharmony_ci } 302cbd624adSopenharmony_ci 303cbd624adSopenharmony_ci // Check if we've exhausted our max digits. 304cbd624adSopenharmony_ci if count == max_digits { 305cbd624adSopenharmony_ci // Need to check if we're truncated, and round-up accordingly. 306cbd624adSopenharmony_ci // SAFETY: safe since `counter <= step`. 307cbd624adSopenharmony_ci add_temporary!(@end format, result, counter, value); 308cbd624adSopenharmony_ci round_up_nonzero!(format, integer, result, count); 309cbd624adSopenharmony_ci round_up_nonzero!(format, fraction, result, count); 310cbd624adSopenharmony_ci return (result, count); 311cbd624adSopenharmony_ci } else { 312cbd624adSopenharmony_ci // Add our temporary from the loop. 313cbd624adSopenharmony_ci // SAFETY: safe since `counter <= step`. 314cbd624adSopenharmony_ci add_temporary!(@max format, result, counter, value, max_native); 315cbd624adSopenharmony_ci } 316cbd624adSopenharmony_ci } 317cbd624adSopenharmony_ci 318cbd624adSopenharmony_ci // Skip leading fraction zeros. 319cbd624adSopenharmony_ci // Required to get an accurate count. 320cbd624adSopenharmony_ci if count == 0 { 321cbd624adSopenharmony_ci for &c in &mut fraction { 322cbd624adSopenharmony_ci if c != b'0' { 323cbd624adSopenharmony_ci add_digit!(c, value, counter, count); 324cbd624adSopenharmony_ci break; 325cbd624adSopenharmony_ci } 326cbd624adSopenharmony_ci } 327cbd624adSopenharmony_ci } 328cbd624adSopenharmony_ci 329cbd624adSopenharmony_ci // Process the fraction digits. 330cbd624adSopenharmony_ci 'fraction: loop { 331cbd624adSopenharmony_ci // Parse a digit at a time, until we reach step. 332cbd624adSopenharmony_ci while counter < step && count < max_digits { 333cbd624adSopenharmony_ci if let Some(&c) = fraction.next() { 334cbd624adSopenharmony_ci add_digit!(c, value, counter, count); 335cbd624adSopenharmony_ci } else { 336cbd624adSopenharmony_ci break 'fraction; 337cbd624adSopenharmony_ci } 338cbd624adSopenharmony_ci } 339cbd624adSopenharmony_ci 340cbd624adSopenharmony_ci // Check if we've exhausted our max digits. 341cbd624adSopenharmony_ci if count == max_digits { 342cbd624adSopenharmony_ci // SAFETY: safe since `counter <= step`. 343cbd624adSopenharmony_ci add_temporary!(@end format, result, counter, value); 344cbd624adSopenharmony_ci round_up_nonzero!(format, fraction, result, count); 345cbd624adSopenharmony_ci return (result, count); 346cbd624adSopenharmony_ci } else { 347cbd624adSopenharmony_ci // Add our temporary from the loop. 348cbd624adSopenharmony_ci // SAFETY: safe since `counter <= step`. 349cbd624adSopenharmony_ci add_temporary!(@max format, result, counter, value, max_native); 350cbd624adSopenharmony_ci } 351cbd624adSopenharmony_ci } 352cbd624adSopenharmony_ci 353cbd624adSopenharmony_ci // We will always have a remainder, as long as we entered the loop 354cbd624adSopenharmony_ci // once, or counter % step is 0. 355cbd624adSopenharmony_ci // SAFETY: safe since `counter <= step`. 356cbd624adSopenharmony_ci add_temporary!(@end format, result, counter, value); 357cbd624adSopenharmony_ci 358cbd624adSopenharmony_ci (result, count) 359cbd624adSopenharmony_ci} 360cbd624adSopenharmony_ci 361cbd624adSopenharmony_ci// SCALING 362cbd624adSopenharmony_ci// ------- 363cbd624adSopenharmony_ci 364cbd624adSopenharmony_ci/// Calculate the scientific exponent from a `Number` value. 365cbd624adSopenharmony_ci/// Any other attempts would require slowdowns for faster algorithms. 366cbd624adSopenharmony_ci#[inline] 367cbd624adSopenharmony_cipub fn scientific_exponent(num: &Number) -> i32 { 368cbd624adSopenharmony_ci // Use power reduction to make this faster. 369cbd624adSopenharmony_ci let mut mantissa = num.mantissa; 370cbd624adSopenharmony_ci let mut exponent = num.exponent; 371cbd624adSopenharmony_ci while mantissa >= 10000 { 372cbd624adSopenharmony_ci mantissa /= 10000; 373cbd624adSopenharmony_ci exponent += 4; 374cbd624adSopenharmony_ci } 375cbd624adSopenharmony_ci while mantissa >= 100 { 376cbd624adSopenharmony_ci mantissa /= 100; 377cbd624adSopenharmony_ci exponent += 2; 378cbd624adSopenharmony_ci } 379cbd624adSopenharmony_ci while mantissa >= 10 { 380cbd624adSopenharmony_ci mantissa /= 10; 381cbd624adSopenharmony_ci exponent += 1; 382cbd624adSopenharmony_ci } 383cbd624adSopenharmony_ci exponent as i32 384cbd624adSopenharmony_ci} 385cbd624adSopenharmony_ci 386cbd624adSopenharmony_ci/// Calculate `b` from a a representation of `b` as a float. 387cbd624adSopenharmony_ci#[inline] 388cbd624adSopenharmony_cipub fn b<F: Float>(float: F) -> ExtendedFloat { 389cbd624adSopenharmony_ci ExtendedFloat { 390cbd624adSopenharmony_ci mant: float.mantissa(), 391cbd624adSopenharmony_ci exp: float.exponent(), 392cbd624adSopenharmony_ci } 393cbd624adSopenharmony_ci} 394cbd624adSopenharmony_ci 395cbd624adSopenharmony_ci/// Calculate `b+h` from a a representation of `b` as a float. 396cbd624adSopenharmony_ci#[inline] 397cbd624adSopenharmony_cipub fn bh<F: Float>(float: F) -> ExtendedFloat { 398cbd624adSopenharmony_ci let fp = b(float); 399cbd624adSopenharmony_ci ExtendedFloat { 400cbd624adSopenharmony_ci mant: (fp.mant << 1) + 1, 401cbd624adSopenharmony_ci exp: fp.exp - 1, 402cbd624adSopenharmony_ci } 403cbd624adSopenharmony_ci} 404