use core::ptr;
pub(crate) const MAX_OUTPUT_STRING_LENGTH: usize =
1 + crate::DECIMAL_SIGNIFICAND_DIGITS + 1 + 1 + 1 + crate::DECIMAL_EXPONENT_DIGITS;
pub(crate) unsafe fn to_chars(x: f64, mut buffer: *mut u8) -> *mut u8 {
let br = x.to_bits();
let s = crate::remove_exponent_bits(br);
if crate::is_negative(s) {
*buffer = b'-';
buffer = buffer.add(1);
}
if crate::is_nonzero(br) {
let result = crate::to_decimal(x);
to_chars_detail(result.significand, result.exponent, buffer)
} else {
*buffer = b'0';
*buffer.add(1) = b'E';
*buffer.add(2) = b'0';
buffer.add(3)
}
}
type BytePair = [u8; 2];
#[rustfmt::skip]
static RADIX_100_TABLE: [BytePair; 100] = [
[b'0', b'0'], [b'0', b'1'], [b'0', b'2'], [b'0', b'3'], [b'0', b'4'],
[b'0', b'5'], [b'0', b'6'], [b'0', b'7'], [b'0', b'8'], [b'0', b'9'],
[b'1', b'0'], [b'1', b'1'], [b'1', b'2'], [b'1', b'3'], [b'1', b'4'],
[b'1', b'5'], [b'1', b'6'], [b'1', b'7'], [b'1', b'8'], [b'1', b'9'],
[b'2', b'0'], [b'2', b'1'], [b'2', b'2'], [b'2', b'3'], [b'2', b'4'],
[b'2', b'5'], [b'2', b'6'], [b'2', b'7'], [b'2', b'8'], [b'2', b'9'],
[b'3', b'0'], [b'3', b'1'], [b'3', b'2'], [b'3', b'3'], [b'3', b'4'],
[b'3', b'5'], [b'3', b'6'], [b'3', b'7'], [b'3', b'8'], [b'3', b'9'],
[b'4', b'0'], [b'4', b'1'], [b'4', b'2'], [b'4', b'3'], [b'4', b'4'],
[b'4', b'5'], [b'4', b'6'], [b'4', b'7'], [b'4', b'8'], [b'4', b'9'],
[b'5', b'0'], [b'5', b'1'], [b'5', b'2'], [b'5', b'3'], [b'5', b'4'],
[b'5', b'5'], [b'5', b'6'], [b'5', b'7'], [b'5', b'8'], [b'5', b'9'],
[b'6', b'0'], [b'6', b'1'], [b'6', b'2'], [b'6', b'3'], [b'6', b'4'],
[b'6', b'5'], [b'6', b'6'], [b'6', b'7'], [b'6', b'8'], [b'6', b'9'],
[b'7', b'0'], [b'7', b'1'], [b'7', b'2'], [b'7', b'3'], [b'7', b'4'],
[b'7', b'5'], [b'7', b'6'], [b'7', b'7'], [b'7', b'8'], [b'7', b'9'],
[b'8', b'0'], [b'8', b'1'], [b'8', b'2'], [b'8', b'3'], [b'8', b'4'],
[b'8', b'5'], [b'8', b'6'], [b'8', b'7'], [b'8', b'8'], [b'8', b'9'],
[b'9', b'0'], [b'9', b'1'], [b'9', b'2'], [b'9', b'3'], [b'9', b'4'],
[b'9', b'5'], [b'9', b'6'], [b'9', b'7'], [b'9', b'8'], [b'9', b'9'],
];
#[rustfmt::skip]
static RADIX_100_HEAD_TABLE: [BytePair; 100] = [
[b'0', b'.'], [b'1', b'.'], [b'2', b'.'], [b'3', b'.'], [b'4', b'.'],
[b'5', b'.'], [b'6', b'.'], [b'7', b'.'], [b'8', b'.'], [b'9', b'.'],
[b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'],
[b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'], [b'1', b'.'],
[b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'],
[b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'], [b'2', b'.'],
[b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'],
[b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'], [b'3', b'.'],
[b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'],
[b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'], [b'4', b'.'],
[b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'],
[b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'], [b'5', b'.'],
[b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'],
[b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'], [b'6', b'.'],
[b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'],
[b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'], [b'7', b'.'],
[b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'],
[b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'], [b'8', b'.'],
[b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'],
[b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'], [b'9', b'.'],
];
unsafe fn print_1_digit(n: u32, buffer: *mut u8) {
const {
assert!((b'0' & 0xf) == 0);
}
*buffer = b'0' | n as u8;
}
unsafe fn print_2_digits(n: u32, buffer: *mut u8) {
let bp = *RADIX_100_TABLE.get_unchecked(n as usize);
*buffer.cast::<BytePair>() = bp;
}
unsafe fn print_head_chars(n: u32, buffer: *mut u8) {
let bp = *RADIX_100_HEAD_TABLE.get_unchecked(n as usize);
*buffer.cast::<BytePair>() = bp;
}
unsafe fn print_9_digits(s32: u32, exponent: &mut i32, buffer: &mut *mut u8) {
if s32 >= 1_0000_0000 {
let mut prod = u64::from(s32) * 1441151882;
prod >>= 25;
print_head_chars((prod >> 32) as u32, *buffer);
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(6));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(8));
*exponent += 8;
*buffer = buffer.add(10);
} else if s32 >= 100_0000 {
let mut prod = u64::from(s32) * 281474978;
prod >>= 16;
let head_digits = (prod >> 32) as u32;
*exponent += 6 + i32::from(head_digits >= 10);
print_head_chars(head_digits, *buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1];
if prod as u32 <= ((1u64 << 32) / 100_0000) as u32 {
*buffer = buffer
.add(1 + (usize::from(head_digits >= 10) & usize::from(*buffer.add(2) > b'0')) * 2);
} else {
*buffer = buffer.add(usize::from(head_digits >= 10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
if prod as u32 <= ((1u64 << 32) / 1_0000) as u32 {
*buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0'));
} else {
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
if prod as u32 <= ((1u64 << 32) / 100) as u32 {
*buffer = buffer.add(5 + usize::from(*buffer.add(5) > b'0'));
} else {
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(6));
*buffer = buffer.add(7 + usize::from(*buffer.add(7) > b'0'));
}
}
}
} else if s32 >= 1_0000 {
let mut prod = u64::from(s32) * 429497;
let head_digits = (prod >> 32) as u32;
*exponent += 4 + i32::from(head_digits >= 10);
print_head_chars(head_digits, *buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1];
if prod as u32 <= ((1u64 << 32) / 1_0000) as u32 {
*buffer = buffer
.add(1 + (usize::from(head_digits >= 10) & usize::from(*buffer.add(2) > b'0')) * 2);
} else {
*buffer = buffer.add(usize::from(head_digits >= 10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
if prod as u32 <= ((1u64 << 32) / 100) as u32 {
*buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0'));
} else {
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
*buffer = buffer.add(5 + usize::from(*buffer.add(5) > b'0'));
}
}
} else if s32 >= 100 {
let mut prod = u64::from(s32) * 42949673;
let head_digits = (prod >> 32) as u32;
*exponent += 2 + i32::from(head_digits >= 10);
print_head_chars(head_digits, *buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1];
if prod as u32 <= ((1u64 << 32) / 100) as u32 {
*buffer = buffer
.add(1 + (usize::from(head_digits >= 10) & usize::from(*buffer.add(2) > b'0')) * 2);
} else {
*buffer = buffer.add(usize::from(head_digits >= 10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
*buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0'));
}
} else {
*exponent += i32::from(s32 >= 10);
print_head_chars(s32, *buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(s32 as usize)[1];
*buffer = buffer.add(1 + (usize::from(s32 >= 10) & usize::from(*buffer.add(2) > b'0')) * 2);
}
}
unsafe fn to_chars_detail(significand: u64, mut exponent: i32, mut buffer: *mut u8) -> *mut u8 {
let first_block: u32;
let second_block: u32;
let no_second_block: bool;
if significand >= 1_0000_0000 {
first_block = (significand / 1_0000_0000) as u32;
second_block = (significand as u32).wrapping_sub(first_block.wrapping_mul(1_0000_0000));
exponent += 8;
no_second_block = second_block == 0;
} else {
first_block = significand as u32;
second_block = 0;
no_second_block = true;
}
if no_second_block {
print_9_digits(first_block, &mut exponent, &mut buffer);
} else {
if first_block >= 1_0000_0000 {
let mut prod = u64::from(first_block) * 1441151882;
prod >>= 25;
print_head_chars((prod >> 32) as u32, buffer);
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(6));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(8));
prod = u64::from(second_block) * 281474978;
prod >>= 16;
prod += 1;
print_2_digits((prod >> 32) as u32, buffer.add(10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(12));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(14));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(16));
exponent += 8;
buffer = buffer.add(18);
} else {
if first_block >= 100_0000 {
let mut prod = u64::from(first_block) * 281474978;
prod >>= 16;
let head_digits = (prod >> 32) as u32;
print_head_chars(head_digits, buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1];
exponent += 6 + i32::from(head_digits >= 10);
buffer = buffer.add(usize::from(head_digits >= 10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(6));
buffer = buffer.add(8);
} else if first_block >= 1_0000 {
let mut prod = u64::from(first_block) * 429497;
let head_digits = (prod >> 32) as u32;
print_head_chars(head_digits, buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1];
exponent += 4 + i32::from(head_digits >= 10);
buffer = buffer.add(usize::from(head_digits >= 10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
buffer = buffer.add(6);
} else if first_block >= 100 {
let mut prod = u64::from(first_block) * 42949673;
let head_digits = (prod >> 32) as u32;
print_head_chars(head_digits, buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(head_digits as usize)[1];
exponent += 2 + i32::from(head_digits >= 10);
buffer = buffer.add(usize::from(head_digits >= 10));
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
buffer = buffer.add(4);
} else {
print_head_chars(first_block, buffer);
*buffer.add(2) = RADIX_100_TABLE.get_unchecked(first_block as usize)[1];
exponent += i32::from(first_block >= 10);
buffer = buffer.add(2 + usize::from(first_block >= 10));
}
let mut prod = u64::from(second_block) * 281474978;
prod >>= 16;
prod += 1;
print_2_digits((prod >> 32) as u32, buffer);
if prod as u32 <= ((1u64 << 32) / 100_0000) as u32 {
buffer = buffer.add(1 + usize::from(*buffer.add(1) > b'0'));
} else {
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(2));
if prod as u32 <= ((1u64 << 32) / 1_0000) as u32 {
buffer = buffer.add(3 + usize::from(*buffer.add(3) > b'0'));
} else {
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(4));
if prod as u32 <= ((1u64 << 32) / 100) as u32 {
buffer = buffer.add(5 + usize::from(*buffer.add(5) > b'0'));
} else {
prod = (prod & 0xffffffff) * 100;
print_2_digits((prod >> 32) as u32, buffer.add(6));
buffer = buffer.add(7 + usize::from(*buffer.add(7) > b'0'));
}
}
}
}
}
if exponent < 0 {
ptr::copy_nonoverlapping(b"E-".as_ptr().cast::<u8>(), buffer, 2);
buffer = buffer.add(2);
exponent = -exponent;
} else {
*buffer = b'E';
buffer = buffer.add(1);
}
if exponent >= 100 {
let d1 = (exponent as u32 * 6554) >> 16;
let d2 = exponent as u32 - 10 * d1;
print_2_digits(d1, buffer);
print_1_digit(d2, buffer.add(2));
buffer = buffer.add(3);
} else if exponent >= 10 {
print_2_digits(exponent as u32, buffer);
buffer = buffer.add(2);
} else {
print_1_digit(exponent as u32, buffer);
buffer = buffer.add(1);
}
buffer
}