1use crate::common::*;
22#[cfg(not(feature = "small"))]
23pub use crate::d2s_full_table::*;
24use crate::d2s_intrinsics::*;
25#[cfg(feature = "small")]
26pub use crate::d2s_small_table::*;
27use core::mem::MaybeUninit;
28
29pub const DOUBLE_MANTISSA_BITS: u32 = 52;
30pub const DOUBLE_EXPONENT_BITS: u32 = 11;
31pub const DOUBLE_BIAS: i32 = 1023;
32pub const DOUBLE_POW5_INV_BITCOUNT: i32 = 125;
33pub const DOUBLE_POW5_BITCOUNT: i32 = 125;
34
35#[cfg_attr(feature = "no-panic", inline)]
36pub fn decimal_length17(v: u64) -> u32 {
37 debug_assert!(v < 100000000000000000);
42
43 if v >= 10000000000000000 {
44 17
45 } else if v >= 1000000000000000 {
46 16
47 } else if v >= 100000000000000 {
48 15
49 } else if v >= 10000000000000 {
50 14
51 } else if v >= 1000000000000 {
52 13
53 } else if v >= 100000000000 {
54 12
55 } else if v >= 10000000000 {
56 11
57 } else if v >= 1000000000 {
58 10
59 } else if v >= 100000000 {
60 9
61 } else if v >= 10000000 {
62 8
63 } else if v >= 1000000 {
64 7
65 } else if v >= 100000 {
66 6
67 } else if v >= 10000 {
68 5
69 } else if v >= 1000 {
70 4
71 } else if v >= 100 {
72 3
73 } else if v >= 10 {
74 2
75 } else {
76 1
77 }
78}
79
80pub struct FloatingDecimal64 {
82 pub mantissa: u64,
83 pub exponent: i32,
86}
87
88#[cfg_attr(feature = "no-panic", inline)]
89pub fn d2d(ieee_mantissa: u64, ieee_exponent: u32) -> FloatingDecimal64 {
90 let (e2, m2) = if ieee_exponent == 0 {
91 (
92 1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2,
94 ieee_mantissa,
95 )
96 } else {
97 (
98 ieee_exponent as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32 - 2,
99 (1u64 << DOUBLE_MANTISSA_BITS) | ieee_mantissa,
100 )
101 };
102 let even = (m2 & 1) == 0;
103 let accept_bounds = even;
104
105 let mv = 4 * m2;
107 let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32;
109 let mut vr: u64;
115 let mut vp: u64;
116 let mut vm: u64;
117 let mut vp_uninit: MaybeUninit<u64> = MaybeUninit::uninit();
118 let mut vm_uninit: MaybeUninit<u64> = MaybeUninit::uninit();
119 let e10: i32;
120 let mut vm_is_trailing_zeros = false;
121 let mut vr_is_trailing_zeros = false;
122 if e2 >= 0 {
123 let q = log10_pow2(e2) - (e2 > 3) as u32;
126 e10 = q as i32;
127 let k = DOUBLE_POW5_INV_BITCOUNT + pow5bits(q as i32) - 1;
128 let i = -e2 + q as i32 + k;
129 vr = unsafe {
130 mul_shift_all_64(
131 m2,
132 #[cfg(feature = "small")]
133 &compute_inv_pow5(q),
134 #[cfg(not(feature = "small"))]
135 {
136 debug_assert!(q < DOUBLE_POW5_INV_SPLIT.len() as u32);
137 DOUBLE_POW5_INV_SPLIT.get_unchecked(q as usize)
138 },
139 i as u32,
140 vp_uninit.as_mut_ptr(),
141 vm_uninit.as_mut_ptr(),
142 mm_shift,
143 )
144 };
145 vp = unsafe { vp_uninit.assume_init() };
146 vm = unsafe { vm_uninit.assume_init() };
147 if q <= 21 {
148 let mv_mod5 = (mv as u32).wrapping_sub(5u32.wrapping_mul(div5(mv) as u32));
152 if mv_mod5 == 0 {
153 vr_is_trailing_zeros = multiple_of_power_of_5(mv, q);
154 } else if accept_bounds {
155 vm_is_trailing_zeros = multiple_of_power_of_5(mv - 1 - mm_shift as u64, q);
159 } else {
160 vp -= multiple_of_power_of_5(mv + 2, q) as u64;
162 }
163 }
164 } else {
165 let q = log10_pow5(-e2) - (-e2 > 1) as u32;
167 e10 = q as i32 + e2;
168 let i = -e2 - q as i32;
169 let k = pow5bits(i) - DOUBLE_POW5_BITCOUNT;
170 let j = q as i32 - k;
171 vr = unsafe {
172 mul_shift_all_64(
173 m2,
174 #[cfg(feature = "small")]
175 &compute_pow5(i as u32),
176 #[cfg(not(feature = "small"))]
177 {
178 debug_assert!(i < DOUBLE_POW5_SPLIT.len() as i32);
179 DOUBLE_POW5_SPLIT.get_unchecked(i as usize)
180 },
181 j as u32,
182 vp_uninit.as_mut_ptr(),
183 vm_uninit.as_mut_ptr(),
184 mm_shift,
185 )
186 };
187 vp = unsafe { vp_uninit.assume_init() };
188 vm = unsafe { vm_uninit.assume_init() };
189 if q <= 1 {
190 vr_is_trailing_zeros = true;
193 if accept_bounds {
194 vm_is_trailing_zeros = mm_shift == 1;
196 } else {
197 vp -= 1;
199 }
200 } else if q < 63 {
201 vr_is_trailing_zeros = multiple_of_power_of_2(mv, q);
207 }
208 }
209
210 let mut removed = 0i32;
212 let mut last_removed_digit = 0u8;
213 let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
215 loop {
217 let vp_div10 = div10(vp);
218 let vm_div10 = div10(vm);
219 if vp_div10 <= vm_div10 {
220 break;
221 }
222 let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32));
223 let vr_div10 = div10(vr);
224 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
225 vm_is_trailing_zeros &= vm_mod10 == 0;
226 vr_is_trailing_zeros &= last_removed_digit == 0;
227 last_removed_digit = vr_mod10 as u8;
228 vr = vr_div10;
229 vp = vp_div10;
230 vm = vm_div10;
231 removed += 1;
232 }
233 if vm_is_trailing_zeros {
234 loop {
235 let vm_div10 = div10(vm);
236 let vm_mod10 = (vm as u32).wrapping_sub(10u32.wrapping_mul(vm_div10 as u32));
237 if vm_mod10 != 0 {
238 break;
239 }
240 let vp_div10 = div10(vp);
241 let vr_div10 = div10(vr);
242 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
243 vr_is_trailing_zeros &= last_removed_digit == 0;
244 last_removed_digit = vr_mod10 as u8;
245 vr = vr_div10;
246 vp = vp_div10;
247 vm = vm_div10;
248 removed += 1;
249 }
250 }
251 if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
252 last_removed_digit = 4;
254 }
255 vr + ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5)
257 as u64
258 } else {
259 let mut round_up = false;
261 let vp_div100 = div100(vp);
262 let vm_div100 = div100(vm);
263 if vp_div100 > vm_div100 {
265 let vr_div100 = div100(vr);
266 let vr_mod100 = (vr as u32).wrapping_sub(100u32.wrapping_mul(vr_div100 as u32));
267 round_up = vr_mod100 >= 50;
268 vr = vr_div100;
269 vp = vp_div100;
270 vm = vm_div100;
271 removed += 2;
272 }
273 loop {
278 let vp_div10 = div10(vp);
279 let vm_div10 = div10(vm);
280 if vp_div10 <= vm_div10 {
281 break;
282 }
283 let vr_div10 = div10(vr);
284 let vr_mod10 = (vr as u32).wrapping_sub(10u32.wrapping_mul(vr_div10 as u32));
285 round_up = vr_mod10 >= 5;
286 vr = vr_div10;
287 vp = vp_div10;
288 vm = vm_div10;
289 removed += 1;
290 }
291 vr + (vr == vm || round_up) as u64
293 };
294 let exp = e10 + removed;
295
296 FloatingDecimal64 {
297 exponent: exp,
298 mantissa: output,
299 }
300}