]> git.proxmox.com Git - rustc.git/blame - vendor/ryu/src/d2s.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / vendor / ryu / src / d2s.rs
CommitLineData
b7449926
XL
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
f035d41b 21use crate::common::*;
b7449926 22#[cfg(not(feature = "small"))]
f035d41b
XL
23pub use crate::d2s_full_table::*;
24use crate::d2s_intrinsics::*;
b7449926 25#[cfg(feature = "small")]
f035d41b
XL
26pub use crate::d2s_small_table::*;
27#[cfg(not(maybe_uninit))]
28use core::mem;
29#[cfg(maybe_uninit)]
30use core::mem::MaybeUninit;
b7449926
XL
31
32pub const DOUBLE_MANTISSA_BITS: u32 = 52;
33pub const DOUBLE_EXPONENT_BITS: u32 = 11;
f035d41b
XL
34pub const DOUBLE_BIAS: i32 = 1023;
35pub const DOUBLE_POW5_INV_BITCOUNT: i32 = 125;
36pub const DOUBLE_POW5_BITCOUNT: i32 = 125;
b7449926
XL
37
38#[cfg_attr(feature = "no-panic", inline)]
416331ca 39pub fn decimal_length17(v: u64) -> u32 {
b7449926
XL
40 // This is slightly faster than a loop.
41 // The average output length is 16.38 digits, so we check high-to-low.
42 // Function precondition: v is not an 18, 19, or 20-digit number.
43 // (17 digits are sufficient for round-tripping.)
44 debug_assert!(v < 100000000000000000);
45
46 if v >= 10000000000000000 {
47 17
48 } else if v >= 1000000000000000 {
49 16
50 } else if v >= 100000000000000 {
51 15
52 } else if v >= 10000000000000 {
53 14
54 } else if v >= 1000000000000 {
55 13
56 } else if v >= 100000000000 {
57 12
58 } else if v >= 10000000000 {
59 11
60 } else if v >= 1000000000 {
61 10
62 } else if v >= 100000000 {
63 9
64 } else if v >= 10000000 {
65 8
66 } else if v >= 1000000 {
67 7
68 } else if v >= 100000 {
69 6
70 } else if v >= 10000 {
71 5
72 } else if v >= 1000 {
73 4
74 } else if v >= 100 {
75 3
76 } else if v >= 10 {
77 2
78 } else {
79 1
80 }
81}
82
83// A floating decimal representing m * 10^e.
84pub struct FloatingDecimal64 {
85 pub mantissa: u64,
416331ca
XL
86 // Decimal exponent's range is -324 to 308
87 // inclusive, and can fit in i16 if needed.
b7449926
XL
88 pub exponent: i32,
89}
90
91#[cfg_attr(feature = "no-panic", inline)]
92pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
b7449926
XL
93 let (e2, m2) = if ieee_exponent == 0 {
94 (
95 // We subtract 2 so that the bounds computation has 2 additional bits.
416331ca 96 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2,
b7449926
XL
97 ieee_mantissa,
98 )
99 } else {
100 (
416331ca 101 ieee_exponent as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2,
b7449926
XL
102 (1u64 << DOUBLE_MANTISSA_BITS) | ieee_mantissa,
103 )
104 };
105 let even = (m2 & 1) == 0;
106 let accept_bounds = even;
107
416331ca 108 // Step 2: Determine the interval of valid decimal representations.
b7449926
XL
109 let mv = 4 * m2;
110 // Implicit bool -> int conversion. True is 1, false is 0.
111 let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32;
112 // We would compute mp and mm like this:
113 // uint64_t mp = 4 * m2 + 2;
114 // uint64_t mm = mv - 1 - mm_shift;
115
116 // Step 3: Convert to a decimal power base using 128-bit arithmetic.
117 let mut vr: u64;
f035d41b
XL
118 let mut vp: u64;
119 let mut vm: u64;
120 #[cfg(not(maybe_uninit))]
121 {
122 vp = unsafe { mem::uninitialized() };
123 vm = unsafe { mem::uninitialized() };
124 }
125 #[cfg(maybe_uninit)]
126 let mut vp_uninit: MaybeUninit<u64> = MaybeUninit::uninit();
127 #[cfg(maybe_uninit)]
128 let mut vm_uninit: MaybeUninit<u64> = MaybeUninit::uninit();
b7449926
XL
129 let e10: i32;
130 let mut vm_is_trailing_zeros = false;
131 let mut vr_is_trailing_zeros = false;
132 if e2 >= 0 {
133 // I tried special-casing q == 0, but there was no effect on performance.
134 // This expression is slightly faster than max(0, log10_pow2(e2) - 1).
416331ca 135 let q = log10_pow2(e2) - (e2 > 3) as u32;
b7449926 136 e10 = q as i32;
416331ca 137 let k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1;
b7449926 138 let i = -e2 + q as i32 + k;
f035d41b
XL
139 vr = unsafe {
140 mul_shift_all_64(
141 m2,
142 #[cfg(feature = "small")]
143 &compute_inv_pow5(q),
144 #[cfg(not(feature = "small"))]
145 {
146 debug_assert!(q < DOUBLE_POW5_INV_SPLIT.len() as u32);
147 DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize)
148 },
149 i as u32,
150 #[cfg(maybe_uninit)]
151 {
152 vp_uninit.as_mut_ptr()
153 },
154 #[cfg(not(maybe_uninit))]
155 {
156 &mut vp
157 },
158 #[cfg(maybe_uninit)]
159 {
160 vm_uninit.as_mut_ptr()
161 },
162 #[cfg(not(maybe_uninit))]
163 {
164 &mut vm
165 },
166 mm_shift,
167 )
168 };
169 #[cfg(maybe_uninit)]
170 {
171 vp = unsafe { vp_uninit.assume_init() };
172 vm = unsafe { vm_uninit.assume_init() };
173 }
b7449926
XL
174 if q <= 21 {
175 // This should use q <= 22, but I think 21 is also safe. Smaller values
176 // may still be safe, but it's more difficult to reason about them.
177 // Only one of mp, mv, and mm can be a multiple of 5, if any.
416331ca 178 let mv_mod5 = (mv as u32).wrapping_sub(5u32.wrapping_mul(div5(mv) as u32));
b7449926
XL
179 if mv_mod5 == 0 {
180 vr_is_trailing_zeros = multiple_of_power_of_5(mv, q);
181 } else if accept_bounds {
182 // Same as min(e2 + (~mm & 1), pow5_factor(mm)) >= q
183 // <=> e2 + (~mm & 1) >= q && pow5_factor(mm) >= q
184 // <=> true && pow5_factor(mm) >= q, since e2 >= q.
185 vm_is_trailing_zeros = multiple_of_power_of_5(mv - 1 - mm_shift as u64, q);
186 } else {
187 // Same as min(e2 + 1, pow5_factor(mp)) >= q.
188 vp -= multiple_of_power_of_5(mv + 2, q) as u64;
189 }
190 }
191 } else {
192 // This expression is slightly faster than max(0, log10_pow5(-e2) - 1).
416331ca 193 let q = log10_pow5(-e2) - (-e2 > 1) as u32;
b7449926
XL
194 e10 = q as i32 + e2;
195 let i = -e2 - q as i32;
416331ca 196 let k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
b7449926 197 let j = q as i32 - k;
f035d41b
XL
198 vr = unsafe {
199 mul_shift_all_64(
200 m2,
201 #[cfg(feature = "small")]
202 &compute_pow5(i as u32),
203 #[cfg(not(feature = "small"))]
204 {
205 debug_assert!(i < DOUBLE_POW5_SPLIT.len() as i32);
206 DOUBLE_POW5_SPLIT.get_unchecked(i as usize)
207 },
208 j as u32,
209 #[cfg(maybe_uninit)]
210 {
211 vp_uninit.as_mut_ptr()
212 },
213 #[cfg(not(maybe_uninit))]
214 {
215 &mut vp
216 },
217 #[cfg(maybe_uninit)]
218 {
219 vm_uninit.as_mut_ptr()
220 },
221 #[cfg(not(maybe_uninit))]
222 {
223 &mut vm
224 },
225 mm_shift,
226 )
227 };
228 #[cfg(maybe_uninit)]
229 {
230 vp = unsafe { vp_uninit.assume_init() };
231 vm = unsafe { vm_uninit.assume_init() };
232 }
b7449926
XL
233 if q <= 1 {
234 // {vr,vp,vm} is trailing zeros if {mv,mp,mm} has at least q trailing 0 bits.
235 // mv = 4 * m2, so it always has at least two trailing 0 bits.
236 vr_is_trailing_zeros = true;
237 if accept_bounds {
238 // mm = mv - 1 - mm_shift, so it has 1 trailing 0 bit iff mm_shift == 1.
239 vm_is_trailing_zeros = mm_shift == 1;
240 } else {
241 // mp = mv + 2, so it always has at least one trailing 0 bit.
242 vp -= 1;
243 }
244 } else if q < 63 {
245 // TODO(ulfjack): Use a tighter bound here.
416331ca
XL
246 // We want to know if the full product has at least q trailing zeros.
247 // We need to compute min(p2(mv), p5(mv) - e2) >= q
248 // <=> p2(mv) >= q && p5(mv) - e2 >= q
249 // <=> p2(mv) >= q (because -e2 >= q)
250 vr_is_trailing_zeros = multiple_of_power_of_2(mv, q);
b7449926
XL
251 }
252 }
253
416331ca
XL
254 // Step 4: Find the shortest decimal representation in the interval of valid representations.
255 let mut removed = 0i32;
b7449926
XL
256 let mut last_removed_digit = 0u8;
257 // On average, we remove ~2 digits.
258 let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
259 // General case, which happens rarely (~0.7%).
260 loop {
261 let vp_div10 = div10(vp);
262 let vm_div10 = div10(vm);
263 if vp_div10 <= vm_div10 {
264 break;
265 }
416331ca 266 let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32));
b7449926 267 let vr_div10 = div10(vr);
416331ca 268 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
b7449926
XL
269 vm_is_trailing_zeros &= vm_mod10 == 0;
270 vr_is_trailing_zeros &= last_removed_digit == 0;
271 last_removed_digit = vr_mod10 as u8;
272 vr = vr_div10;
273 vp = vp_div10;
274 vm = vm_div10;
275 removed += 1;
276 }
277 if vm_is_trailing_zeros {
278 loop {
279 let vm_div10 = div10(vm);
416331ca 280 let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32));
b7449926
XL
281 if vm_mod10 != 0 {
282 break;
283 }
284 let vp_div10 = div10(vp);
285 let vr_div10 = div10(vr);
416331ca 286 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
b7449926
XL
287 vr_is_trailing_zeros &= last_removed_digit == 0;
288 last_removed_digit = vr_mod10 as u8;
289 vr = vr_div10;
290 vp = vp_div10;
291 vm = vm_div10;
292 removed += 1;
293 }
294 }
295 if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
296 // Round even if the exact number is .....50..0.
297 last_removed_digit = 4;
298 }
299 // We need to take vr + 1 if vr is outside bounds or we need to round up.
300 vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
301 as u64
302 } else {
303 // Specialized for the common case (~99.3%). Percentages below are relative to this.
304 let mut round_up = false;
305 let vp_div100 = div100(vp);
306 let vm_div100 = div100(vm);
307 // Optimization: remove two digits at a time (~86.2%).
308 if vp_div100 > vm_div100 {
309 let vr_div100 = div100(vr);
416331ca 310 let vr_mod100 = (vr as u32).wrapping_sub(100u32.wrapping_mul(vr_div100 as u32));
b7449926
XL
311 round_up = vr_mod100 >= 50;
312 vr = vr_div100;
313 vp = vp_div100;
314 vm = vm_div100;
315 removed += 2;
316 }
317 // Loop iterations below (approximately), without optimization above:
318 // 0: 0.03%, 1: 13.8%, 2: 70.6%, 3: 14.0%, 4: 1.40%, 5: 0.14%, 6+: 0.02%
319 // Loop iterations below (approximately), with optimization above:
320 // 0: 70.6%, 1: 27.8%, 2: 1.40%, 3: 0.14%, 4+: 0.02%
321 loop {
322 let vp_div10 = div10(vp);
323 let vm_div10 = div10(vm);
324 if vp_div10 <= vm_div10 {
325 break;
326 }
327 let vr_div10 = div10(vr);
416331ca 328 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
b7449926
XL
329 round_up = vr_mod10 >= 5;
330 vr = vr_div10;
331 vp = vp_div10;
332 vm = vm_div10;
333 removed += 1;
334 }
335 // We need to take vr + 1 if vr is outside bounds or we need to round up.
336 vr + (vr == vm || round_up) as u64
337 };
416331ca 338 let exp = e10 + removed;
b7449926
XL
339
340 FloatingDecimal64 {
341 exponent: exp,
342 mantissa: output,
343 }
344}