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