use std::{io, mem, ptr, slice};
const DEC_DIGITS_LUT: &'static[u8] =
b"0001020304050607080910111213141516171819\
2021222324252627282930313233343536373839\
4041424344454647484950515253545556575859\
6061626364656667686970717273747576777879\
8081828384858687888990919293949596979899";
const ZEROFILL: &'static [u8] = &[b'0'; 20];
#[inline(always)]
unsafe fn write_num(n: &mut u64, curr: &mut isize, buf_ptr: *mut u8, lut_ptr: *const u8) {
while *n >= 10000 {
let rem = (*n % 10000) as isize;
*n /= 10000;
let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
*curr -= 4;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(*curr), 2);
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(*curr + 2), 2);
}
if *n >= 100 {
let d1 = ((*n % 100) << 1) as isize;
*n /= 100;
*curr -= 2;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(*curr), 2);
}
if *n < 10 {
*curr -= 1;
*buf_ptr.offset(*curr) = (*n as u8) + b'0';
} else {
let d1 = (*n << 1) as isize;
*curr -= 2;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(*curr), 2);
}
}
pub unsafe fn write<W: io::Write>(wr: &mut W, positive: bool, mut n: u64, exponent: i16) -> io::Result<()> {
if !positive {
wr.write_all(b"-")?;
}
if n == 0 {
return wr.write_all(b"0");
}
const BUF_LEN: usize = 30;
let mut buf = mem::MaybeUninit::<[u8; BUF_LEN]>::uninit();
let mut curr = BUF_LEN as isize;
let buf_ptr = buf.as_mut_ptr() as *mut u8;
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
if exponent == 0 {
write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
return wr.write_all(
slice::from_raw_parts(
buf_ptr.offset(curr),
BUF_LEN - curr as usize
)
);
} else if exponent < 0 {
let mut e = safe_abs(exponent);
if e < 18 {
for _ in 0 .. e >> 2 {
let rem = (n % 10000) as isize;
n /= 10000;
let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
curr -= 4;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
}
e &= 3;
if e & 2 == 2 {
let d1 = ((n % 100) << 1) as isize;
n /= 100;
curr -= 2;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
}
if e & 1 == 1 {
curr -= 1;
*buf_ptr.offset(curr) = ((n % 10) as u8) + b'0';
n /= 10;
}
curr -= 1;
*buf_ptr.offset(curr) = b'.';
write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
return wr.write_all(
slice::from_raw_parts(buf_ptr.offset(curr), BUF_LEN - curr as usize)
);
}
let mut exponent_positive = false;
if n < 10 {
curr -= 1;
*buf_ptr.offset(curr) = ((n % 10) as u8) + b'0';
} else {
while n >= 100000 {
let rem = (n % 10000) as isize;
n /= 10000;
let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
curr -= 4;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
}
if n >= 1000 {
let d1 = ((n % 100) << 1) as isize;
n /= 100;
curr -= 2;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
}
if n < 100 {
curr -= 1;
*buf_ptr.offset(curr) = ((n % 10) as u8) + b'0';
n /= 10;
} else {
let d1 = ((n % 100) << 1) as isize;
n /= 100;
curr -= 2;
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
}
let printed_so_far = BUF_LEN as u16 - curr as u16;
if printed_so_far <= e {
e -= printed_so_far;
} else {
e = printed_so_far - e;
exponent_positive = true;
}
curr -= 1;
*buf_ptr.offset(curr) = b'.';
write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
}
wr.write_all(
slice::from_raw_parts(
buf_ptr.offset(curr),
BUF_LEN - curr as usize
)
)?;
if e == 0 {
return Ok(());
}
if exponent_positive {
wr.write_all(b"e+")?;
} else {
wr.write_all(b"e-")?;
}
return write(wr, true, e as u64, 0);
}
write_num(&mut n, &mut curr, buf_ptr, lut_ptr);
let printed = BUF_LEN - curr as usize;
if (printed + exponent as usize) <= 20 {
wr.write_all(
slice::from_raw_parts(
buf_ptr.offset(curr),
BUF_LEN - curr as usize
)
)?;
return wr.write_all(&ZEROFILL[ .. exponent as usize]);
}
let mut e = exponent as u64;
if printed != 1 {
*buf_ptr.offset(curr - 1) = *buf_ptr.offset(curr);
*buf_ptr.offset(curr) = b'.';
curr -= 1;
e += (printed as u64) - 1;
}
wr.write_all(
slice::from_raw_parts(
buf_ptr.offset(curr),
BUF_LEN - curr as usize
)
)?;
wr.write_all(b"e")?;
write(wr, true, e, 0)
}
fn safe_abs(x : i16) -> u16 {
if let Some(y) = x.checked_abs() {
y as u16
} else {
i16::max_value() as u16 + 1u16
}
}