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 | |