1use core::ptr;
22
23#[cfg(maybe_uninit)]
24use core::mem::MaybeUninit;
25
26#[cfg(not(maybe_uninit))]
27use core::mem;
28
29use common::*;
30#[cfg(not(feature = "small"))]
31use d2s_full_table::*;
32use d2s_intrinsics::*;
33#[cfg(feature = "small")]
34use d2s_small_table::*;
35
36pub const DOUBLE_MANTISSA_BITS: u32 = 52;
37pub const DOUBLE_EXPONENT_BITS: u32 = 11;
38
39const DOUBLE_BIAS: i32 = 1023;
40const DOUBLE_POW5_INV_BITCOUNT: i32 = 122;
41const DOUBLE_POW5_BITCOUNT: i32 = 121;
42
43#[cfg(integer128)]
44#[cfg_attr(feature = "no-panic", inline)]
45fn mul_shift(m: u64, mul: &(u64, u64), j: u32) -> u64 {
46 let b0 = m as u128 * mul.0 as u128;
47 let b2 = m as u128 * mul.1 as u128;
48 (((b0 >> 64) + b2) >> (j - 64)) as u64
49}
50
51#[cfg(integer128)]
52#[cfg_attr(feature = "no-panic", inline)]
53unsafe fn mul_shift_all(
54 m: u64,
55 mul: &(u64, u64),
56 j: u32,
57 vp: *mut u64,
58 vm: *mut u64,
59 mm_shift: u32,
60) -> u64 {
61 ptr::write(vp, mul_shift(4 * m + 2, mul, j));
62 ptr::write(vm, mul_shift(4 * m - 1 - mm_shift as u64, mul, j));
63 mul_shift(4 * m, mul, j)
64}
65
66#[cfg(not(integer128))]
67#[cfg_attr(feature = "no-panic", inline)]
68unsafe fn mul_shift_all(
69 mut m: u64,
70 mul: &(u64, u64),
71 j: u32,
72 vp: *mut u64,
73 vm: *mut u64,
74 mm_shift: u32,
75) -> u64 {
76 m <<= 1;
77 let (lo, tmp) = umul128(m, mul.0);
79 let (mut mid, mut hi) = umul128(m, mul.1);
80 mid = mid.wrapping_add(tmp);
81 hi = hi.wrapping_add((mid < tmp) as u64); let lo2 = lo.wrapping_add(mul.0);
84 let mid2 = mid.wrapping_add(mul.1).wrapping_add((lo2 < lo) as u64);
85 let hi2 = hi.wrapping_add((mid2 < mid) as u64);
86 ptr::write(vp, shiftright128(mid2, hi2, j - 64 - 1));
87
88 if mm_shift == 1 {
89 let lo3 = lo.wrapping_sub(mul.0);
90 let mid3 = mid.wrapping_sub(mul.1).wrapping_sub((lo3 > lo) as u64);
91 let hi3 = hi.wrapping_sub((mid3 > mid) as u64);
92 ptr::write(vm, shiftright128(mid3, hi3, j - 64 - 1));
93 } else {
94 let lo3 = lo + lo;
95 let mid3 = mid.wrapping_add(mid).wrapping_add((lo3 < lo) as u64);
96 let hi3 = hi.wrapping_add(hi).wrapping_add((mid3 < mid) as u64);
97 let lo4 = lo3.wrapping_sub(mul.0);
98 let mid4 = mid3.wrapping_sub(mul.1).wrapping_sub((lo4 > lo3) as u64);
99 let hi4 = hi3.wrapping_sub((mid4 > mid3) as u64);
100 ptr::write(vm, shiftright128(mid4, hi4, j - 64));
101 }
102
103 shiftright128(mid, hi, j - 64 - 1)
104}
105
106#[cfg_attr(feature = "no-panic", inline)]
107pub fn decimal_length17(v: u64) -> u32 {
108 debug_assert!(v < 100000000000000000);
113
114 if v >= 10000000000000000 {
115 17
116 } else if v >= 1000000000000000 {
117 16
118 } else if v >= 100000000000000 {
119 15
120 } else if v >= 10000000000000 {
121 14
122 } else if v >= 1000000000000 {
123 13
124 } else if v >= 100000000000 {
125 12
126 } else if v >= 10000000000 {
127 11
128 } else if v >= 1000000000 {
129 10
130 } else if v >= 100000000 {
131 9
132 } else if v >= 10000000 {
133 8
134 } else if v >= 1000000 {
135 7
136 } else if v >= 100000 {
137 6
138 } else if v >= 10000 {
139 5
140 } else if v >= 1000 {
141 4
142 } else if v >= 100 {
143 3
144 } else if v >= 10 {
145 2
146 } else {
147 1
148 }
149}
150
151pub struct FloatingDecimal64 {
153 pub mantissa: u64,
154 pub exponent: i32,
157}
158
159#[cfg_attr(feature = "no-panic", inline)]
160pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
161 let (e2, m2) = if ieee_exponent == 0 {
162 (
163 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2,
165 ieee_mantissa,
166 )
167 } else {
168 (
169 ieee_exponent as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2,
170 (1u64 << DOUBLE_MANTISSA_BITS) | ieee_mantissa,
171 )
172 };
173 let even = (m2 & 1) == 0;
174 let accept_bounds = even;
175
176 let mv = 4 * m2;
178 let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32;
180 let mut vr: u64;
186 let mut vp: u64;
187 let mut vm: u64;
188 #[cfg(not(maybe_uninit))]
189 {
190 vp = unsafe { mem::uninitialized() };
191 vm = unsafe { mem::uninitialized() };
192 }
193 #[cfg(maybe_uninit)]
194 let mut vp_uninit: MaybeUninit<u64> = MaybeUninit::uninit();
195 #[cfg(maybe_uninit)]
196 let mut vm_uninit: MaybeUninit<u64> = MaybeUninit::uninit();
197 let e10: i32;
198 let mut vm_is_trailing_zeros = false;
199 let mut vr_is_trailing_zeros = false;
200 if e2 >= 0 {
201 let q = log10_pow2(e2) - (e2 > 3) as u32;
204 e10 = q as i32;
205 let k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1;
206 let i = -e2 + q as i32 + k;
207 vr = unsafe {
208 mul_shift_all(
209 m2,
210 #[cfg(feature = "small")]
211 &compute_inv_pow5(q),
212 #[cfg(not(feature = "small"))]
213 {
214 debug_assert!(q < DOUBLE_POW5_INV_SPLIT.len() as u32);
215 DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize)
216 },
217 i as u32,
218 #[cfg(maybe_uninit)]
219 {
220 vp_uninit.as_mut_ptr()
221 },
222 #[cfg(not(maybe_uninit))]
223 {
224 &mut vp
225 },
226 #[cfg(maybe_uninit)]
227 {
228 vm_uninit.as_mut_ptr()
229 },
230 #[cfg(not(maybe_uninit))]
231 {
232 &mut vm
233 },
234 mm_shift,
235 )
236 };
237 #[cfg(maybe_uninit)]
238 {
239 vp = unsafe { vp_uninit.assume_init() };
240 vm = unsafe { vm_uninit.assume_init() };
241 }
242 if q <= 21 {
243 let mv_mod5 = (mv as u32).wrapping_sub(5u32.wrapping_mul(div5(mv) as u32));
247 if mv_mod5 == 0 {
248 vr_is_trailing_zeros = multiple_of_power_of_5(mv, q);
249 } else if accept_bounds {
250 vm_is_trailing_zeros = multiple_of_power_of_5(mv - 1 - mm_shift as u64, q);
254 } else {
255 vp -= multiple_of_power_of_5(mv + 2, q) as u64;
257 }
258 }
259 } else {
260 let q = log10_pow5(-e2) - (-e2 > 1) as u32;
262 e10 = q as i32 + e2;
263 let i = -e2 - q as i32;
264 let k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
265 let j = q as i32 - k;
266 vr = unsafe {
267 mul_shift_all(
268 m2,
269 #[cfg(feature = "small")]
270 &compute_pow5(i as u32),
271 #[cfg(not(feature = "small"))]
272 {
273 debug_assert!(i < DOUBLE_POW5_SPLIT.len() as i32);
274 DOUBLE_POW5_SPLIT.get_unchecked(i as usize)
275 },
276 j as u32,
277 #[cfg(maybe_uninit)]
278 {
279 vp_uninit.as_mut_ptr()
280 },
281 #[cfg(not(maybe_uninit))]
282 {
283 &mut vp
284 },
285 #[cfg(maybe_uninit)]
286 {
287 vm_uninit.as_mut_ptr()
288 },
289 #[cfg(not(maybe_uninit))]
290 {
291 &mut vm
292 },
293 mm_shift,
294 )
295 };
296 #[cfg(maybe_uninit)]
297 {
298 vp = unsafe { vp_uninit.assume_init() };
299 vm = unsafe { vm_uninit.assume_init() };
300 }
301 if q <= 1 {
302 vr_is_trailing_zeros = true;
305 if accept_bounds {
306 vm_is_trailing_zeros = mm_shift == 1;
308 } else {
309 vp -= 1;
311 }
312 } else if q < 63 {
313 vr_is_trailing_zeros = multiple_of_power_of_2(mv, q);
319 }
320 }
321
322 let mut removed = 0i32;
324 let mut last_removed_digit = 0u8;
325 let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
327 loop {
329 let vp_div10 = div10(vp);
330 let vm_div10 = div10(vm);
331 if vp_div10 <= vm_div10 {
332 break;
333 }
334 let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32));
335 let vr_div10 = div10(vr);
336 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
337 vm_is_trailing_zeros &= vm_mod10 == 0;
338 vr_is_trailing_zeros &= last_removed_digit == 0;
339 last_removed_digit = vr_mod10 as u8;
340 vr = vr_div10;
341 vp = vp_div10;
342 vm = vm_div10;
343 removed += 1;
344 }
345 if vm_is_trailing_zeros {
346 loop {
347 let vm_div10 = div10(vm);
348 let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32));
349 if vm_mod10 != 0 {
350 break;
351 }
352 let vp_div10 = div10(vp);
353 let vr_div10 = div10(vr);
354 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
355 vr_is_trailing_zeros &= last_removed_digit == 0;
356 last_removed_digit = vr_mod10 as u8;
357 vr = vr_div10;
358 vp = vp_div10;
359 vm = vm_div10;
360 removed += 1;
361 }
362 }
363 if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
364 last_removed_digit = 4;
366 }
367 vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
369 as u64
370 } else {
371 let mut round_up = false;
373 let vp_div100 = div100(vp);
374 let vm_div100 = div100(vm);
375 if vp_div100 > vm_div100 {
377 let vr_div100 = div100(vr);
378 let vr_mod100 = (vr as u32).wrapping_sub(100u32.wrapping_mul(vr_div100 as u32));
379 round_up = vr_mod100 >= 50;
380 vr = vr_div100;
381 vp = vp_div100;
382 vm = vm_div100;
383 removed += 2;
384 }
385 loop {
390 let vp_div10 = div10(vp);
391 let vm_div10 = div10(vm);
392 if vp_div10 <= vm_div10 {
393 break;
394 }
395 let vr_div10 = div10(vr);
396 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
397 round_up = vr_mod10 >= 5;
398 vr = vr_div10;
399 vp = vp_div10;
400 vm = vm_div10;
401 removed += 1;
402 }
403 vr + (vr == vm || round_up) as u64
405 };
406 let exp = e10 + removed;
407
408 FloatingDecimal64 {
409 exponent: exp,
410 mantissa: output,
411 }
412}