| 1 | // Translated from C to Rust. The original C code can be found at | 
| 2 | // https://github.com/ulfjack/ryu and carries the following license: | 
|---|
| 3 | // | 
|---|
| 4 | // Copyright 2018 Ulf Adams | 
|---|
| 5 | // | 
|---|
| 6 | // The contents of this file may be used under the terms of the Apache License, | 
|---|
| 7 | // Version 2.0. | 
|---|
| 8 | // | 
|---|
| 9 | //    (See accompanying file LICENSE-Apache or copy at | 
|---|
| 10 | //     http://www.apache.org/licenses/LICENSE-2.0) | 
|---|
| 11 | // | 
|---|
| 12 | // Alternatively, the contents of this file may be used under the terms of | 
|---|
| 13 | // the Boost Software License, Version 1.0. | 
|---|
| 14 | //    (See accompanying file LICENSE-Boost or copy at | 
|---|
| 15 | //     https://www.boost.org/LICENSE_1_0.txt) | 
|---|
| 16 | // | 
|---|
| 17 | // Unless required by applicable law or agreed to in writing, this software | 
|---|
| 18 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
|---|
| 19 | // KIND, either express or implied. | 
|---|
| 20 |  | 
|---|
| 21 | use crate::d2s; | 
|---|
| 22 |  | 
|---|
| 23 | pub const FLOAT_POW5_INV_BITCOUNT: i32 = d2s::DOUBLE_POW5_INV_BITCOUNT - 64; | 
|---|
| 24 | pub const FLOAT_POW5_BITCOUNT: i32 = d2s::DOUBLE_POW5_BITCOUNT - 64; | 
|---|
| 25 |  | 
|---|
| 26 | #[ cfg_attr(feature = "no-panic", inline)] | 
|---|
| 27 | fn pow5factor_32(mut value: u32) -> u32 { | 
|---|
| 28 | let mut count: u32 = 0u32; | 
|---|
| 29 | loop { | 
|---|
| 30 | debug_assert!(value != 0); | 
|---|
| 31 | let q: u32 = value / 5; | 
|---|
| 32 | let r: u32 = value % 5; | 
|---|
| 33 | if r != 0 { | 
|---|
| 34 | break; | 
|---|
| 35 | } | 
|---|
| 36 | value = q; | 
|---|
| 37 | count += 1; | 
|---|
| 38 | } | 
|---|
| 39 | count | 
|---|
| 40 | } | 
|---|
| 41 |  | 
|---|
| 42 | // Returns true if value is divisible by 5^p. | 
|---|
| 43 | #[ cfg_attr(feature = "no-panic", inline)] | 
|---|
| 44 | pub fn multiple_of_power_of_5_32(value: u32, p: u32) -> bool { | 
|---|
| 45 | pow5factor_32(value) >= p | 
|---|
| 46 | } | 
|---|
| 47 |  | 
|---|
| 48 | // Returns true if value is divisible by 2^p. | 
|---|
| 49 | #[ cfg_attr(feature = "no-panic", inline)] | 
|---|
| 50 | pub fn multiple_of_power_of_2_32(value: u32, p: u32) -> bool { | 
|---|
| 51 | // __builtin_ctz doesn't appear to be faster here. | 
|---|
| 52 | (value & ((1u32 << p) - 1)) == 0 | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | // It seems to be slightly faster to avoid uint128_t here, although the | 
|---|
| 56 | // generated code for uint128_t looks slightly nicer. | 
|---|
| 57 | #[ cfg_attr(feature = "no-panic", inline)] | 
|---|
| 58 | fn mul_shift_32(m: u32, factor: u64, shift: i32) -> u32 { | 
|---|
| 59 | debug_assert!(shift > 32); | 
|---|
| 60 |  | 
|---|
| 61 | // The casts here help MSVC to avoid calls to the __allmul library | 
|---|
| 62 | // function. | 
|---|
| 63 | let factor_lo: u32 = factor as u32; | 
|---|
| 64 | let factor_hi: u32 = (factor >> 32) as u32; | 
|---|
| 65 | let bits0: u64 = m as u64 * factor_lo as u64; | 
|---|
| 66 | let bits1: u64 = m as u64 * factor_hi as u64; | 
|---|
| 67 |  | 
|---|
| 68 | let sum: u64 = (bits0 >> 32) + bits1; | 
|---|
| 69 | let shifted_sum: u64 = sum >> (shift - 32); | 
|---|
| 70 | debug_assert!(shifted_sum <= u32::max_value() as u64); | 
|---|
| 71 | shifted_sum as u32 | 
|---|
| 72 | } | 
|---|
| 73 |  | 
|---|
| 74 | #[ cfg_attr(feature = "no-panic", inline)] | 
|---|
| 75 | pub fn mul_pow5_inv_div_pow2(m: u32, q: u32, j: i32) -> u32 { | 
|---|
| 76 | #[ cfg(feature = "small")] | 
|---|
| 77 | { | 
|---|
| 78 | // The inverse multipliers are defined as [2^x / 5^y] + 1; the upper 64 | 
|---|
| 79 | // bits from the double lookup table are the correct bits for [2^x / | 
|---|
| 80 | // 5^y], so we have to add 1 here. Note that we rely on the fact that | 
|---|
| 81 | // the added 1 that's already stored in the table never overflows into | 
|---|
| 82 | // the upper 64 bits. | 
|---|
| 83 | let pow5 = unsafe { d2s::compute_inv_pow5(q) }; | 
|---|
| 84 | mul_shift_32(m, pow5.1 + 1, j) | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | #[ cfg(not(feature = "small"))] | 
|---|
| 88 | { | 
|---|
| 89 | debug_assert!(q < d2s::DOUBLE_POW5_INV_SPLIT.len() as u32); | 
|---|
| 90 | unsafe { | 
|---|
| 91 | mul_shift_32( | 
|---|
| 92 | m, | 
|---|
| 93 | factor:d2s::DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize).1 + 1, | 
|---|
| 94 | shift:j, | 
|---|
| 95 | ) | 
|---|
| 96 | } | 
|---|
| 97 | } | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | #[ cfg_attr(feature = "no-panic", inline)] | 
|---|
| 101 | pub fn mul_pow5_div_pow2(m: u32, i: u32, j: i32) -> u32 { | 
|---|
| 102 | #[ cfg(feature = "small")] | 
|---|
| 103 | { | 
|---|
| 104 | let pow5 = unsafe { d2s::compute_pow5(i) }; | 
|---|
| 105 | mul_shift_32(m, pow5.1, j) | 
|---|
| 106 | } | 
|---|
| 107 |  | 
|---|
| 108 | #[ cfg(not(feature = "small"))] | 
|---|
| 109 | { | 
|---|
| 110 | debug_assert!(i < d2s::DOUBLE_POW5_SPLIT.len() as u32); | 
|---|
| 111 | unsafe { mul_shift_32(m, factor:d2s::DOUBLE_POW5_SPLIT.get_unchecked(i as usize).1, shift:j) } | 
|---|
| 112 | } | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|