| 1 | // Adapted from https://github.com/Alexhuszagh/rust-lexical. |
| 2 | |
| 3 | //! Compare the mantissa to the halfway representation of the float. |
| 4 | //! |
| 5 | //! Compares the actual significant digits of the mantissa to the |
| 6 | //! theoretical digits from `b+h`, scaled into the proper range. |
| 7 | |
| 8 | use super::bignum::*; |
| 9 | use super::digit::*; |
| 10 | use super::exponent::*; |
| 11 | use super::float::*; |
| 12 | use super::math::*; |
| 13 | use super::num::*; |
| 14 | use super::rounding::*; |
| 15 | use core::{cmp, mem}; |
| 16 | |
| 17 | // MANTISSA |
| 18 | |
| 19 | /// Parse the full mantissa into a big integer. |
| 20 | /// |
| 21 | /// Max digits is the maximum number of digits plus one. |
| 22 | fn parse_mantissa<F>(integer: &[u8], fraction: &[u8]) -> Bigint |
| 23 | where |
| 24 | F: Float, |
| 25 | { |
| 26 | // Main loop |
| 27 | let small_powers = POW10_LIMB; |
| 28 | let step = small_powers.len() - 2; |
| 29 | let max_digits = F::MAX_DIGITS - 1; |
| 30 | let mut counter = 0; |
| 31 | let mut value: Limb = 0; |
| 32 | let mut i: usize = 0; |
| 33 | let mut result = Bigint::default(); |
| 34 | |
| 35 | // Iteratively process all the data in the mantissa. |
| 36 | for &digit in integer.iter().chain(fraction) { |
| 37 | // We've parsed the max digits using small values, add to bignum |
| 38 | if counter == step { |
| 39 | result.imul_small(small_powers[counter]); |
| 40 | result.iadd_small(value); |
| 41 | counter = 0; |
| 42 | value = 0; |
| 43 | } |
| 44 | |
| 45 | value *= 10; |
| 46 | value += as_limb(to_digit(digit).unwrap()); |
| 47 | |
| 48 | i += 1; |
| 49 | counter += 1; |
| 50 | if i == max_digits { |
| 51 | break; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | // We will always have a remainder, as long as we entered the loop |
| 56 | // once, or counter % step is 0. |
| 57 | if counter != 0 { |
| 58 | result.imul_small(small_powers[counter]); |
| 59 | result.iadd_small(value); |
| 60 | } |
| 61 | |
| 62 | // If we have any remaining digits after the last value, we need |
| 63 | // to add a 1 after the rest of the array, it doesn't matter where, |
| 64 | // just move it up. This is good for the worst-possible float |
| 65 | // representation. We also need to return an index. |
| 66 | // Since we already trimmed trailing zeros, we know there has |
| 67 | // to be a non-zero digit if there are any left. |
| 68 | if i < integer.len() + fraction.len() { |
| 69 | result.imul_small(10); |
| 70 | result.iadd_small(1); |
| 71 | } |
| 72 | |
| 73 | result |
| 74 | } |
| 75 | |
| 76 | // FLOAT OPS |
| 77 | |
| 78 | /// Calculate `b` from a a representation of `b` as a float. |
| 79 | #[inline ] |
| 80 | pub(super) fn b_extended<F: Float>(f: F) -> ExtendedFloat { |
| 81 | ExtendedFloat::from_float(f) |
| 82 | } |
| 83 | |
| 84 | /// Calculate `b+h` from a a representation of `b` as a float. |
| 85 | #[inline ] |
| 86 | pub(super) fn bh_extended<F: Float>(f: F) -> ExtendedFloat { |
| 87 | // None of these can overflow. |
| 88 | let b = b_extended(f); |
| 89 | ExtendedFloat { |
| 90 | mant: (b.mant << 1) + 1, |
| 91 | exp: b.exp - 1, |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | // ROUNDING |
| 96 | |
| 97 | /// Custom round-nearest, tie-event algorithm for bhcomp. |
| 98 | #[inline ] |
| 99 | fn round_nearest_tie_even(fp: &mut ExtendedFloat, shift: i32, is_truncated: bool) { |
| 100 | let (mut is_above, mut is_halfway) = round_nearest(fp, shift); |
| 101 | if is_halfway && is_truncated { |
| 102 | is_above = true; |
| 103 | is_halfway = false; |
| 104 | } |
| 105 | tie_even(fp, is_above, is_halfway); |
| 106 | } |
| 107 | |
| 108 | // BHCOMP |
| 109 | |
| 110 | /// Calculate the mantissa for a big integer with a positive exponent. |
| 111 | fn large_atof<F>(mantissa: Bigint, exponent: i32) -> F |
| 112 | where |
| 113 | F: Float, |
| 114 | { |
| 115 | let bits = mem::size_of::<u64>() * 8; |
| 116 | |
| 117 | // Simple, we just need to multiply by the power of the radix. |
| 118 | // Now, we can calculate the mantissa and the exponent from this. |
| 119 | // The binary exponent is the binary exponent for the mantissa |
| 120 | // shifted to the hidden bit. |
| 121 | let mut bigmant = mantissa; |
| 122 | bigmant.imul_pow10(exponent as u32); |
| 123 | |
| 124 | // Get the exact representation of the float from the big integer. |
| 125 | let (mant, is_truncated) = bigmant.hi64(); |
| 126 | let exp = bigmant.bit_length() as i32 - bits as i32; |
| 127 | let mut fp = ExtendedFloat { mant, exp }; |
| 128 | fp.round_to_native::<F, _>(|fp, shift| round_nearest_tie_even(fp, shift, is_truncated)); |
| 129 | into_float(fp) |
| 130 | } |
| 131 | |
| 132 | /// Calculate the mantissa for a big integer with a negative exponent. |
| 133 | /// |
| 134 | /// This invokes the comparison with `b+h`. |
| 135 | fn small_atof<F>(mantissa: Bigint, exponent: i32, f: F) -> F |
| 136 | where |
| 137 | F: Float, |
| 138 | { |
| 139 | // Get the significant digits and radix exponent for the real digits. |
| 140 | let mut real_digits = mantissa; |
| 141 | let real_exp = exponent; |
| 142 | debug_assert!(real_exp < 0); |
| 143 | |
| 144 | // Get the significant digits and the binary exponent for `b+h`. |
| 145 | let theor = bh_extended(f); |
| 146 | let mut theor_digits = Bigint::from_u64(theor.mant); |
| 147 | let theor_exp = theor.exp; |
| 148 | |
| 149 | // We need to scale the real digits and `b+h` digits to be the same |
| 150 | // order. We currently have `real_exp`, in `radix`, that needs to be |
| 151 | // shifted to `theor_digits` (since it is negative), and `theor_exp` |
| 152 | // to either `theor_digits` or `real_digits` as a power of 2 (since it |
| 153 | // may be positive or negative). Try to remove as many powers of 2 |
| 154 | // as possible. All values are relative to `theor_digits`, that is, |
| 155 | // reflect the power you need to multiply `theor_digits` by. |
| 156 | |
| 157 | // Can remove a power-of-two, since the radix is 10. |
| 158 | // Both are on opposite-sides of equation, can factor out a |
| 159 | // power of two. |
| 160 | // |
| 161 | // Example: 10^-10, 2^-10 -> ( 0, 10, 0) |
| 162 | // Example: 10^-10, 2^-15 -> (-5, 10, 0) |
| 163 | // Example: 10^-10, 2^-5 -> ( 5, 10, 0) |
| 164 | // Example: 10^-10, 2^5 -> (15, 10, 0) |
| 165 | let binary_exp = theor_exp - real_exp; |
| 166 | let halfradix_exp = -real_exp; |
| 167 | let radix_exp = 0; |
| 168 | |
| 169 | // Carry out our multiplication. |
| 170 | if halfradix_exp != 0 { |
| 171 | theor_digits.imul_pow5(halfradix_exp as u32); |
| 172 | } |
| 173 | if radix_exp != 0 { |
| 174 | theor_digits.imul_pow10(radix_exp as u32); |
| 175 | } |
| 176 | if binary_exp > 0 { |
| 177 | theor_digits.imul_pow2(binary_exp as u32); |
| 178 | } else if binary_exp < 0 { |
| 179 | real_digits.imul_pow2(-binary_exp as u32); |
| 180 | } |
| 181 | |
| 182 | // Compare real digits to theoretical digits and round the float. |
| 183 | match real_digits.compare(&theor_digits) { |
| 184 | cmp::Ordering::Greater => f.next_positive(), |
| 185 | cmp::Ordering::Less => f, |
| 186 | cmp::Ordering::Equal => f.round_positive_even(), |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | /// Calculate the exact value of the float. |
| 191 | /// |
| 192 | /// Note: fraction must not have trailing zeros. |
| 193 | pub(crate) fn bhcomp<F>(b: F, integer: &[u8], mut fraction: &[u8], exponent: i32) -> F |
| 194 | where |
| 195 | F: Float, |
| 196 | { |
| 197 | // Calculate the number of integer digits and use that to determine |
| 198 | // where the significant digits start in the fraction. |
| 199 | let integer_digits = integer.len(); |
| 200 | let fraction_digits = fraction.len(); |
| 201 | let digits_start = if integer_digits == 0 { |
| 202 | let start = fraction.iter().take_while(|&x| *x == b'0' ).count(); |
| 203 | fraction = &fraction[start..]; |
| 204 | start |
| 205 | } else { |
| 206 | 0 |
| 207 | }; |
| 208 | let sci_exp = scientific_exponent(exponent, integer_digits, digits_start); |
| 209 | let count = F::MAX_DIGITS.min(integer_digits + fraction_digits - digits_start); |
| 210 | let scaled_exponent = sci_exp + 1 - count as i32; |
| 211 | |
| 212 | let mantissa = parse_mantissa::<F>(integer, fraction); |
| 213 | if scaled_exponent >= 0 { |
| 214 | large_atof(mantissa, scaled_exponent) |
| 215 | } else { |
| 216 | small_atof(mantissa, scaled_exponent, b) |
| 217 | } |
| 218 | } |
| 219 | |