1use core::{mem, ptr};
22
23use common::*;
24use digit_table::*;
25
26#[cfg(feature = "no-panic")]
27use no_panic::no_panic;
28
29pub const FLOAT_MANTISSA_BITS: u32 = 23;
30pub const FLOAT_EXPONENT_BITS: u32 = 8;
31
32const FLOAT_POW5_INV_BITCOUNT: i32 = 59;
33const FLOAT_POW5_BITCOUNT: i32 = 61;
34
35static FLOAT_POW5_INV_SPLIT: [u64; 32] = [576460752303423489,
37 461168601842738791,
38 368934881474191033,
39 295147905179352826,
40 472236648286964522,
41 377789318629571618,
42 302231454903657294,
43 483570327845851670,
44 386856262276681336,
45 309485009821345069,
46 495176015714152110,
47 396140812571321688,
48 316912650057057351,
49 507060240091291761,
50 405648192073033409,
51 324518553658426727,
52 519229685853482763,
53 415383748682786211,
54 332306998946228969,
55 531691198313966350,
56 425352958651173080,
57 340282366920938464,
58 544451787073501542,
59 435561429658801234,
60 348449143727040987,
61 557518629963265579,
62 446014903970612463,
63 356811923176489971,
64 570899077082383953,
65 456719261665907162,
66 365375409332725730,
67 1 << 63];
68
69static FLOAT_POW5_SPLIT: [u64; 47] = [1152921504606846976,
70 1441151880758558720,
71 1801439850948198400,
72 2251799813685248000,
73 1407374883553280000,
74 1759218604441600000,
75 2199023255552000000,
76 1374389534720000000,
77 1717986918400000000,
78 2147483648000000000,
79 1342177280000000000,
80 1677721600000000000,
81 2097152000000000000,
82 1310720000000000000,
83 1638400000000000000,
84 2048000000000000000,
85 1280000000000000000,
86 1600000000000000000,
87 2000000000000000000,
88 1250000000000000000,
89 1562500000000000000,
90 1953125000000000000,
91 1220703125000000000,
92 1525878906250000000,
93 1907348632812500000,
94 1192092895507812500,
95 1490116119384765625,
96 1862645149230957031,
97 1164153218269348144,
98 1455191522836685180,
99 1818989403545856475,
100 2273736754432320594,
101 1421085471520200371,
102 1776356839400250464,
103 2220446049250313080,
104 1387778780781445675,
105 1734723475976807094,
106 2168404344971008868,
107 1355252715606880542,
108 1694065894508600678,
109 2117582368135750847,
110 1323488980084844279,
111 1654361225106055349,
112 2067951531382569187,
113 1292469707114105741,
114 1615587133892632177,
115 2019483917365790221];
116
117#[cfg_attr(feature = "no-panic", inline)]
118fn pow5_factor(mut value: u32) -> u32 {
119 let mut count = 0u32;
120 loop {
121 debug_assert!(value != 0);
122 let q = value / 5;
123 let r = value % 5;
124 if r != 0 {
125 break;
126 }
127 value = q;
128 count += 1;
129 }
130 count
131}
132
133#[cfg_attr(feature = "no-panic", inline)]
135fn multiple_of_power_of_5(value: u32, p: u32) -> bool {
136 pow5_factor(value) >= p
137}
138
139#[cfg_attr(feature = "no-panic", inline)]
141fn multiple_of_power_of_2(value: u32, p: u32) -> bool {
142 (value & ((1u32 << p) - 1)) == 0
144}
145
146#[cfg_attr(feature = "no-panic", inline)]
149fn mul_shift(m: u32, factor: u64, shift: i32) -> u32 {
150 debug_assert!(shift > 32);
151
152 let factor_lo = factor as u32;
155 let factor_hi = (factor >> 32) as u32;
156 let bits0 = m as u64 * factor_lo as u64;
157 let bits1 = m as u64 * factor_hi as u64;
158
159 let sum = (bits0 >> 32) + bits1;
160 let shifted_sum = sum >> (shift - 32);
161 debug_assert!(shifted_sum <= u32::max_value() as u64);
162 shifted_sum as u32
163}
164
165#[cfg_attr(feature = "no-panic", inline)]
166fn mul_pow5_inv_div_pow2(m: u32, q: u32, j: i32) -> u32 {
167 debug_assert!(q < FLOAT_POW5_INV_SPLIT.len() as u32);
168 unsafe { mul_shift(m, *FLOAT_POW5_INV_SPLIT.get_unchecked(q as usize), j) }
169}
170
171#[cfg_attr(feature = "no-panic", inline)]
172fn mul_pow5_div_pow2(m: u32, i: u32, j: i32) -> u32 {
173 debug_assert!(i < FLOAT_POW5_SPLIT.len() as u32);
174 unsafe { mul_shift(m, *FLOAT_POW5_SPLIT.get_unchecked(i as usize), j) }
175}
176
177#[cfg_attr(feature = "no-panic", inline)]
178pub fn decimal_length(v: u32) -> u32 {
179 debug_assert!(v < 1000000000);
182
183 if v >= 100000000 {
184 9
185 } else if v >= 10000000 {
186 8
187 } else if v >= 1000000 {
188 7
189 } else if v >= 100000 {
190 6
191 } else if v >= 10000 {
192 5
193 } else if v >= 1000 {
194 4
195 } else if v >= 100 {
196 3
197 } else if v >= 10 {
198 2
199 } else {
200 1
201 }
202}
203
204pub struct FloatingDecimal32 {
206 pub mantissa: u32,
207 pub exponent: i32,
208}
209
210#[cfg_attr(feature = "no-panic", inline)]
211pub fn f2d(ieee_mantissa: u32, ieee_exponent: u32) -> FloatingDecimal32 {
212 let bias = (1u32 << (FLOAT_EXPONENT_BITS - 1)) - 1;
213
214 let (e2, m2) = if ieee_exponent == 0 {
215 (1 - bias as i32 - FLOAT_MANTISSA_BITS as i32 - 2,
217 ieee_mantissa)
218 } else {
219 (ieee_exponent as i32 - bias as i32 - FLOAT_MANTISSA_BITS as i32 - 2,
220 (1u32 << FLOAT_MANTISSA_BITS) | ieee_mantissa)
221 };
222 let even = (m2 & 1) == 0;
223 let accept_bounds = even;
224
225 let mv = 4 * m2;
227 let mp = 4 * m2 + 2;
228 let mm_shift = (ieee_mantissa != 0 || ieee_exponent <= 1) as u32;
230 let mm = 4 * m2 - 1 - mm_shift;
231
232 let mut vr: u32;
234 let mut vp: u32;
235 let mut vm: u32;
236 let e10: i32;
237 let mut vm_is_trailing_zeros = false;
238 let mut vr_is_trailing_zeros = false;
239 let mut last_removed_digit = 0u8;
240 if e2 >= 0 {
241 let q = log10_pow2(e2) as u32;
242 e10 = q as i32;
243 let k = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32) as i32 - 1;
244 let i = -e2 + q as i32 + k;
245 vr = mul_pow5_inv_div_pow2(mv, q, i);
246 vp = mul_pow5_inv_div_pow2(mp, q, i);
247 vm = mul_pow5_inv_div_pow2(mm, q, i);
248 if q != 0 && (vp - 1) / 10 <= vm / 10 {
249 let l = FLOAT_POW5_INV_BITCOUNT + pow5bits(q as i32 - 1) as i32 - 1;
253 last_removed_digit = (mul_pow5_inv_div_pow2(mv, q - 1, -e2 + q as i32 - 1 + l) %
254 10) as u8;
255 }
256 if q <= 9 {
257 if mv % 5 == 0 {
260 vr_is_trailing_zeros = multiple_of_power_of_5(mv, q);
261 } else if accept_bounds {
262 vm_is_trailing_zeros = multiple_of_power_of_5(mm, q);
263 } else {
264 vp -= multiple_of_power_of_5(mp, q) as u32;
265 }
266 }
267 } else {
268 let q = log10_pow5(-e2) as u32;
269 e10 = q as i32 + e2;
270 let i = -e2 - q as i32;
271 let k = pow5bits(i) as i32 - FLOAT_POW5_BITCOUNT;
272 let mut j = q as i32 - k;
273 vr = mul_pow5_div_pow2(mv, i as u32, j);
274 vp = mul_pow5_div_pow2(mp, i as u32, j);
275 vm = mul_pow5_div_pow2(mm, i as u32, j);
276 if q != 0 && (vp - 1) / 10 <= vm / 10 {
277 j = q as i32 - 1 - (pow5bits(i + 1) as i32 - FLOAT_POW5_BITCOUNT);
278 last_removed_digit = (mul_pow5_div_pow2(mv, (i + 1) as u32, j) % 10) as u8;
279 }
280 if q <= 1 {
281 vr_is_trailing_zeros = true;
284 if accept_bounds {
285 vm_is_trailing_zeros = mm_shift == 1;
287 } else {
288 vp -= 1;
290 }
291 } else if q < 31 {
292 vr_is_trailing_zeros = multiple_of_power_of_2(mv, q - 1);
294 }
295 }
296
297 let mut removed = 0u32;
299 let output = if vm_is_trailing_zeros || vr_is_trailing_zeros {
300 while vp / 10 > vm / 10 {
302 vm_is_trailing_zeros &= vm - (vm / 10) * 10 == 0;
303 vr_is_trailing_zeros &= last_removed_digit == 0;
304 last_removed_digit = (vr % 10) as u8;
305 vr /= 10;
306 vp /= 10;
307 vm /= 10;
308 removed += 1;
309 }
310 if vm_is_trailing_zeros {
311 while vm % 10 == 0 {
312 vr_is_trailing_zeros &= last_removed_digit == 0;
313 last_removed_digit = (vr % 10) as u8;
314 vr /= 10;
315 vp /= 10;
316 vm /= 10;
317 removed += 1;
318 }
319 }
320 if vr_is_trailing_zeros && last_removed_digit == 5 && vr % 2 == 0 {
321 last_removed_digit = 4;
323 }
324 vr +
326 ((vr == vm && (!accept_bounds || !vm_is_trailing_zeros)) || last_removed_digit >= 5) as u32
327 } else {
328 while vp / 10 > vm / 10 {
332 last_removed_digit = (vr % 10) as u8;
333 vr /= 10;
334 vp /= 10;
335 vm /= 10;
336 removed += 1;
337 }
338 vr + (vr == vm || last_removed_digit >= 5) as u32
340 };
341 let exp = e10 + removed as i32;
342
343 FloatingDecimal32 {
344 exponent: exp,
345 mantissa: output,
346 }
347}
348
349#[cfg_attr(feature = "no-panic", inline)]
350unsafe fn to_chars(v: FloatingDecimal32, sign: bool, result: *mut u8) -> usize {
351 let mut index = 0isize;
353 if sign {
354 *result.offset(index) = b'-';
355 index += 1;
356 }
357
358 let mut output = v.mantissa;
359 let olength = decimal_length(output);
360
361 let mut i = 0isize;
369 while output >= 10000 {
370 let c = output - 10000 * (output / 10000);
371 output /= 10000;
372 let c0 = (c % 100) << 1;
373 let c1 = (c / 100) << 1;
374 ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c0 as usize),
375 result.offset(index + olength as isize - i - 1),
376 2);
377 ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c1 as usize),
378 result.offset(index + olength as isize - i - 3),
379 2);
380 i += 4;
381 }
382 if output >= 100 {
383 let c = (output % 100) << 1;
384 output /= 100;
385 ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked(c as usize),
386 result.offset(index + olength as isize - i - 1),
387 2);
388 i += 2;
389 }
390 if output >= 10 {
391 let c = output << 1;
392 *result.offset(index + olength as isize - i) = *DIGIT_TABLE.get_unchecked(c as usize + 1);
394 *result.offset(index) = *DIGIT_TABLE.get_unchecked(c as usize);
395 } else {
396 *result.offset(index) = b'0' + output as u8;
397 }
398
399 if olength > 1 {
401 *result.offset(index + 1) = b'.';
402 index += olength as isize + 1;
403 } else {
404 index += 1;
405 }
406
407 *result.offset(index) = b'E';
409 index += 1;
410 let mut exp = v.exponent + olength as i32 - 1;
411 if exp < 0 {
412 *result.offset(index) = b'-';
413 index += 1;
414 exp = -exp;
415 }
416
417 if exp >= 10 {
418 ptr::copy_nonoverlapping(DIGIT_TABLE.get_unchecked((2 * exp) as usize),
419 result.offset(index),
420 2);
421 index += 2;
422 } else {
423 *result.offset(index) = b'0' + exp as u8;
424 index += 1;
425 }
426
427 debug_assert!(index <= 15);
428 index as usize
429}
430
431#[cfg_attr(must_use_return, must_use)]
458#[cfg_attr(feature = "no-panic", no_panic)]
459pub unsafe fn f2s_buffered_n(f: f32, result: *mut u8) -> usize {
460 let bits = mem::transmute::<f32, u32>(f);
462
463 let ieee_sign = ((bits >> (FLOAT_MANTISSA_BITS + FLOAT_EXPONENT_BITS)) & 1) != 0;
465 let ieee_mantissa = bits & ((1u32 << FLOAT_MANTISSA_BITS) - 1);
466 let ieee_exponent = ((bits >> FLOAT_MANTISSA_BITS) & ((1u32 << FLOAT_EXPONENT_BITS) - 1)) as
467 u32;
468
469 if ieee_exponent == ((1u32 << FLOAT_EXPONENT_BITS) - 1) ||
471 (ieee_exponent == 0 && ieee_mantissa == 0) {
472 return copy_special_str(result, ieee_sign, ieee_exponent != 0, ieee_mantissa != 0);
473 }
474
475 let v = f2d(ieee_mantissa, ieee_exponent);
476 to_chars(v, ieee_sign, result)
477}