1use crate::{
2 d2s::{DOUBLE_BIAS, DOUBLE_EXPONENT_BITS, DOUBLE_MANTISSA_BITS},
3 digit_table::DIGIT_TABLE,
4 pretty::{
5 format64,
6 to_fixed::d2fixed_full_table::{
7 ADDITIONAL_BITS_2, MIN_BLOCK_2, POW10_OFFSET, POW10_OFFSET_2, POW10_SPLIT,
8 POW10_SPLIT_2,
9 },
10 },
11};
12#[cfg(feature = "no-panic")]
13use no_panic::no_panic;
14
15mod d2fixed_full_table;
16
17pub const MAX_BUFFER_SIZE: usize = 132;
28
29pub struct Cursor {
30 buffer: *mut u8,
31 len: isize,
32 index: isize,
33}
34
35impl Cursor {
36 #[cfg_attr(feature = "no-panic", no_panic)]
37 pub fn new(buffer: *mut u8, len: usize) -> Self {
38 debug_assert!(!buffer.is_null());
39 Self {
40 buffer,
41 len: len as isize,
42 index: 0,
43 }
44 }
45
46 #[cfg_attr(feature = "no-panic", no_panic)]
52 unsafe fn append_byte(&mut self, c: u8) {
53 debug_assert!(self.index < self.len);
54
55 *self.buffer.offset(self.index) = c;
56 self.index += 1;
57 }
58
59 #[cfg_attr(feature = "no-panic", no_panic)]
65 unsafe fn append_bytes(&mut self, c: u8, count: usize) {
66 debug_assert!(self.index + count as isize <= self.len);
67
68 self.buffer.offset(self.index).write_bytes(c, count);
69 self.index += count as isize;
70 }
71
72 #[cfg_attr(feature = "no-panic", no_panic)]
76 fn index(&self) -> usize {
77 self.index as usize
78 }
79
80 #[cfg_attr(feature = "no-panic", no_panic)]
87 unsafe fn append_nine_digits(&mut self, mut digits: u32) {
88 let count = 9;
89
90 debug_assert!(self.index + count <= self.len);
91
92 if digits == 0 {
93 self.append_bytes(b'0', 9);
94 return;
95 }
96
97 let result = self.buffer.offset(self.index);
98
99 for i in [0, 4] {
100 let c = digits % 10000;
101 digits /= 10000;
102 let c0 = (c % 100) << 1;
103 let c1 = (c / 100) << 1;
104
105 result
108 .offset(7 - i as isize)
109 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c0 as isize), 2);
110 result
111 .offset(5 - i as isize)
112 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c1 as isize), 2);
113 }
114 *(result.offset(0)) = b'0' + digits as u8;
115
116 self.index += count;
117 }
118
119 #[cfg_attr(feature = "no-panic", no_panic)]
130 unsafe fn append_n_digits(&mut self, mut digits: u32) {
131 let olength = decimal_length9(digits);
132
133 debug_assert!(self.index + olength as isize <= self.len);
134
135 let result = self.buffer.offset(self.index);
136
137 let mut i = 0;
138 while digits >= 10000 {
139 let c = digits % 10000;
140
141 digits /= 10000;
142 let c0 = (c % 100) << 1;
143 let c1 = (c / 100) << 1;
144
145 result
148 .offset(olength as isize - i as isize - 2)
149 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c0 as isize), 2);
150 result
151 .offset(olength as isize - i as isize - 4)
152 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c1 as isize), 2);
153
154 i += 4;
155 }
156 if digits >= 100 {
157 let c = (digits % 100) << 1;
158 digits /= 100;
159
160 result
162 .offset(olength as isize - i as isize - 2)
163 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c as isize), 2);
164
165 i += 2;
166 }
167 if digits >= 10 {
168 let c = digits << 1;
169
170 result
172 .offset(olength as isize - i as isize - 2)
173 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c as isize), 2);
174 } else {
175 *result = b'0' + digits as u8;
176 }
177
178 self.index += olength as isize;
179 }
180
181 #[cfg_attr(feature = "no-panic", no_panic)]
188 unsafe fn append_c_digits(&mut self, count: u32, mut digits: u32) {
189 debug_assert!(self.index + count as isize <= self.len);
190
191 let result = self.buffer.offset(self.index);
192
193 let mut i: u32 = 0;
195 while i < count - 1 {
197 let c: u32 = (digits % 100) << 1;
198 digits /= 100;
199
200 result
202 .offset((count - i - 2) as isize)
203 .copy_from_nonoverlapping(DIGIT_TABLE.as_ptr().offset(c as isize), 2);
204
205 i += 2;
206 }
207 if i < count {
209 let c = b'0' + (digits % 10) as u8;
210
211 *result.offset((count - i - 1) as isize) = c;
213 }
214
215 self.index += count as isize;
216 }
217
218 #[cfg_attr(feature = "no-panic", no_panic)]
224 unsafe fn get(&mut self, i: isize) -> u8 {
225 debug_assert!((0..self.len).contains(&i));
226
227 *self.buffer.offset(i)
228 }
229
230 #[cfg_attr(feature = "no-panic", no_panic)]
236 unsafe fn set(&mut self, i: isize, c: u8) {
237 debug_assert!((0..self.len).contains(&i));
238
239 *self.buffer.offset(i) = c;
240 }
241}
242
243const MAX_EXPONENT: u32 = 0b100_0100_0100; const MIN_EXPONENT: u16 = 0b010_1001_0011;
248
249const MAX_E2: i32 = MAX_EXPONENT as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32;
251const MIN_E2: i32 = MIN_EXPONENT as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32;
252
253const MAX_POW10_SPLIT_2_INX: i32 = -MIN_E2 / 16;
254
255const POW10_ADDITIONAL_BITS: u32 = 120;
256
257#[cfg_attr(feature = "no-panic", no_panic)]
259fn log10_pow2(e: i32) -> u32 {
260 debug_assert!((0..=1650).contains(&e));
262
263 ((e as u32) * 78913) >> 18
264}
265
266#[cfg_attr(feature = "no-panic", no_panic)]
270fn index_for_exponent(e: u32) -> u32 {
271 debug_assert!((0..=MAX_E2 as u32).contains(&e));
272
273 let result = (e + 15) / 16;
274
275 debug_assert!((0..=2).contains(&result));
276
277 result
278}
279
280#[cfg_attr(feature = "no-panic", no_panic)]
281fn pow10_bits_for_index(idx: u32) -> u32 {
282 16 * idx + POW10_ADDITIONAL_BITS
283}
284
285#[cfg_attr(feature = "no-panic", no_panic)]
291fn length_for_index(idx: u32) -> u32 {
292 (log10_pow2(16 * idx as i32) + 1 + 16 + 8) / 9
294}
295
296#[cfg_attr(feature = "no-panic", no_panic)]
297fn umul256(a: u128, b_hi: u64, b_lo: u64) -> (u128, u128) {
298 let a_lo = a as u64;
299 let a_hi = (a >> 64) as u64;
300
301 let b00 = (a_lo as u128) * (b_lo as u128);
302 let b01 = (a_lo as u128) * (b_hi as u128);
303 let b10 = (a_hi as u128) * (b_lo as u128);
304 let b11 = (a_hi as u128) * (b_hi as u128);
305
306 let b00_lo = b00 as u64;
307 let b00_hi = (b00 >> 64) as u64;
308
309 let mid1 = b10 + b00_hi as u128;
310 let mid1_lo = (mid1) as u64;
311 let mid1_hi = (mid1 >> 64) as u64;
312
313 let mid2 = b01 + mid1_lo as u128;
314 let mid2_lo = (mid2) as u64;
315 let mid2_hi = (mid2 >> 64) as u64;
316
317 let p_hi = b11 + mid1_hi as u128 + mid2_hi as u128;
318 let p_lo = ((mid2_lo as u128) << 64) | b00_lo as u128;
319
320 (p_hi, p_lo)
321}
322
323#[cfg_attr(feature = "no-panic", no_panic)]
325fn umul256_hi(a: u128, b_hi: u64, b_lo: u64) -> u128 {
326 let (hi, _lo) = umul256(a, b_hi, b_lo);
330 hi
331}
332
333#[cfg_attr(feature = "no-panic", no_panic)]
336fn uint128_mod1e9(v: u128) -> u32 {
337 let multiplied = umul256_hi(v, 0x89705F4136B4A597, 0x31680A88F8953031) as u64;
340
341 let shifted = (multiplied >> 29) as u32;
343
344 (v as u32).wrapping_sub(1000000000u32.wrapping_mul(shifted))
345}
346
347#[cfg_attr(feature = "no-panic", no_panic)]
349fn mul_shift_mod1e9(m: u64, mul: &[u64; 3], j: i32) -> u32 {
350 let b0 = m as u128 * mul[0] as u128; let b1 = m as u128 * mul[1] as u128; let b2 = m as u128 * mul[2] as u128; debug_assert!((128..=180).contains(&j));
355
356 let mid = b1 + ((b0 >> 64) as u64) as u128; let s1 = b2 + ((mid >> 64) as u64) as u128; uint128_mod1e9(s1 >> (j - 128))
359}
360
361#[cfg_attr(feature = "no-panic", no_panic)]
363fn decimal_length9(v: u32) -> u32 {
364 debug_assert!(v < 1000000000);
368
369 if v >= 100000000 {
370 9
371 } else if v >= 10000000 {
372 8
373 } else if v >= 1000000 {
374 7
375 } else if v >= 100000 {
376 6
377 } else if v >= 10000 {
378 5
379 } else if v >= 1000 {
380 4
381 } else if v >= 100 {
382 3
383 } else if v >= 10 {
384 2
385 } else {
386 1
387 }
388}
389
390#[must_use]
430#[cfg_attr(feature = "no-panic", no_panic)]
431pub unsafe fn format64_to_fixed(f: f64, fraction_digits: u8, result: *mut u8) -> usize {
432 debug_assert!((0..=100).contains(&fraction_digits));
438
439 let f_abs = if f < 0.0 { -f } else { f };
441 if f_abs >= 1e21 {
442 return format64(f, result);
444 }
445
446 let mut result = Cursor::new(result, MAX_BUFFER_SIZE);
447
448 let bits = f.to_bits();
449 let sign = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
450 let ieee_mantissa = bits & ((1u64 << DOUBLE_MANTISSA_BITS) - 1);
451 let ieee_exponent =
452 (bits >> DOUBLE_MANTISSA_BITS) as u32 & ((1u32 << DOUBLE_EXPONENT_BITS) - 1);
453
454 if ieee_exponent == 0 && ieee_mantissa == 0 {
460 result.append_byte(b'0');
461 if fraction_digits == 0 {
462 return result.index();
463 }
464 result.append_byte(b'.');
465 result.append_bytes(b'0', fraction_digits as usize);
466 return result.index();
467 }
468
469 debug_assert!((0..=MAX_EXPONENT).contains(&ieee_exponent));
470
471 if sign {
472 result.append_byte(b'-');
473 }
474
475 let (e2, m2) = if ieee_exponent == 0 {
476 (1 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32, ieee_mantissa)
477 } else {
478 (
479 ieee_exponent as i32 - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS as i32,
480 (1 << DOUBLE_MANTISSA_BITS) | ieee_mantissa,
481 )
482 };
483
484 debug_assert!((..=MAX_E2).contains(&e2));
485
486 let mut nonzero = false;
487
488 if e2 >= -(DOUBLE_MANTISSA_BITS as i32) {
492 let idx = if e2 < 0 {
494 0
495 } else {
496 index_for_exponent(e2 as u32)
497 };
498 let p10bits = pow10_bits_for_index(idx);
499 let len = length_for_index(idx) as i32;
500
501 for i in (0..len).rev() {
502 let j = p10bits as i32 - e2;
503 let split_idx = *POW10_OFFSET.get_unchecked(idx as usize) as usize;
505
506 let mul = POW10_SPLIT.get_unchecked(split_idx + i as usize);
509
510 let digits = mul_shift_mod1e9(m2 << 8, mul, j + 8);
513 if nonzero {
514 result.append_nine_digits(digits);
515 } else if digits != 0 {
516 result.append_n_digits(digits);
517 nonzero = true;
518 }
519 }
520 }
521
522 if !nonzero {
524 result.append_byte(b'0');
525 }
526
527 if fraction_digits != 0 {
529 result.append_byte(b'.');
530 }
531
532 if e2 >= 0 {
534 result.append_bytes(b'0', fraction_digits as usize);
535 return result.index();
536 }
537
538 let fraction_digits = fraction_digits as u32;
543
544 let idx = (-e2 / 16).min(MAX_POW10_SPLIT_2_INX) as usize;
545
546 let min_block = MIN_BLOCK_2[idx];
547
548 let blocks: u32 = fraction_digits / 9 + 1;
552 if blocks <= min_block as u32 {
553 result.append_bytes(b'0', fraction_digits as usize);
554 return result.index();
555 }
556
557 debug_assert!(idx <= 25);
558
559 let mut round_up = false;
560
561 for i in 0..blocks {
562 let p: isize = POW10_OFFSET_2[idx] as isize + i as isize - min_block as isize;
563 debug_assert!(p >= 0);
564 let p = p as usize;
565
566 if p >= *POW10_OFFSET_2.get_unchecked(idx + 1) as usize {
572 let fill = fraction_digits as usize - 9 * i as usize;
575 result.append_bytes(b'0', fill);
577 break;
578 }
579
580 debug_assert!(p <= 480);
581
582 let j: isize = ADDITIONAL_BITS_2 as isize + (-(e2 as isize) - 16 * idx as isize);
585
586 let mut digits: u32 =
595 mul_shift_mod1e9(m2 << 8, POW10_SPLIT_2.get_unchecked(p), j as i32 + 8);
596
597 if i < blocks - 1 {
598 result.append_nine_digits(digits);
599 } else {
600 let maximum: u32 = fraction_digits - 9 * i;
601 let mut last_digit: u32 = 0;
602 for _k in 0..(9 - maximum) {
603 last_digit = digits % 10;
604 digits /= 10;
605 }
606
607 round_up = last_digit >= 5;
609
610 if maximum != 0 {
611 result.append_c_digits(maximum, digits);
612 }
613 break;
614 }
615 }
616
617 if round_up {
619 let mut round_index = result.index;
620 let mut dot_index = 0; loop {
622 round_index -= 1;
623
624 let c = result.get(round_index);
625 if round_index == -1 || c == b'-' {
626 result.set(round_index + 1, b'1');
627 if dot_index > 0 {
628 result.set(dot_index, b'0');
629 result.set(dot_index + 1, b'.');
630 }
631 result.append_byte(b'0');
632 break;
633 }
634 if c == b'.' {
635 dot_index = round_index;
636 continue;
637 } else if c == b'9' {
638 result.set(round_index, b'0');
639 continue;
640 }
641
642 result.set(round_index, c + 1);
643 break;
644 }
645 }
646
647 result.index()
648}