use itoa;
use lib::{mem, ptr};
use util::*;
#[inline]
pub(crate) fn naive_exponent(d: f64, radix: u32) -> i32
{
(d.ln() / (radix as f64).ln()).floor() as i32
}
unsafe extern "C" fn ftoa_naive(value: f64, radix: u32, first: *mut u8)
-> *mut u8
{
debug_assert_radix!(radix);
debug_assert!(!value.is_special());
debug_assert!(value != 0.0);
debug_assert!(value > 0.0);
const MAX_NONDIGIT_LENGTH: usize = 25;
const MAX_DIGIT_LENGTH: usize = BUFFER_SIZE - MAX_NONDIGIT_LENGTH;
const SIZE: usize = 2200;
let mut buffer: [u8; SIZE] = mem::uninitialized();
let buffer = buffer.as_mut_ptr();
let initial_position: usize = SIZE / 2;
let mut integer_cursor = initial_position;
let mut fraction_cursor = initial_position;
let base = radix as f64;
let mut integer = value.floor();
let mut fraction = value - integer;
let mut delta = 0.5 * (value.next_positive() - value);
delta = 0.0.next_positive().max_finite(delta);
debug_assert!(delta > 0.0);
if fraction > delta {
loop {
fraction *= base;
delta *= base;
let digit = fraction as i32;
*buffer.add(fraction_cursor) = digit_to_char(digit);
fraction_cursor += 1;
fraction -= digit as f64;
if fraction > 0.5 || (fraction == 0.5 && (digit & 1) != 0) {
if fraction + delta > 1.0 {
loop {
fraction_cursor -= 1;
if fraction_cursor == initial_position-1 {
integer += 1.0;
break;
}
let c = *buffer.add(fraction_cursor);
let digit = char_to_digit(c) as i32;
if digit <= radix as i32 {
let idx = (digit + 1) as usize;
*buffer.add(fraction_cursor) = digit_to_char(idx);
fraction_cursor += 1;
break;
}
}
break;
}
}
if delta >= fraction {
break;
}
}
}
while (integer / base).exponent() > 0 {
integer /= base;
integer_cursor -= 1;
*buffer.add(integer_cursor) = b'0';
}
loop {
let remainder = integer % base;
integer_cursor -= 1;
let idx = remainder as usize;
*buffer.add(integer_cursor) = digit_to_char(idx);
integer = (integer - remainder) / base;
if integer <= 0.0 {
break;
}
};
if value <= 1e-5 || value >= 1e9 {
let exponent = naive_exponent(value, radix);
let start: usize;
let end: usize;
if value <= 1e-5 {
start = ((initial_position as i32) - exponent - 1) as usize;
end = fraction_cursor.min(start + MAX_DIGIT_LENGTH + 1);
} else {
start = integer_cursor;
end = fraction_cursor.min(start + MAX_DIGIT_LENGTH + 1);
}
let mut buf_first = buffer.add(start);
let mut buf_last = buf_first.add(end - start);
loop {
buf_last = buf_last.sub(1);
if *buf_last != b'0' {
break;
}
}
let mut p = first;
*p = *buf_first;
p = p.add(1);
buf_first = buf_first.add(1);
*p = b'.';
p = p.add(1);
let dist = distance(buf_first, buf_last);
ptr::copy_nonoverlapping(buf_first, p, dist);
p = p.add(dist);
*p = exponent_notation_char(radix);
let exp: u32;
p = p.add(1);
if exponent < 0 {
*p = b'-';
p = p.add(1);
exp = exponent.wrapping_neg() as u32;
} else {
exp = exponent as u32;
}
return itoa::forward(exp, radix, p);
} else {
let mut p;
let integer_length = initial_position - integer_cursor;
let fraction_length = (fraction_cursor - initial_position).min(MAX_DIGIT_LENGTH - integer_length);
ptr::copy_nonoverlapping(buffer.add(integer_cursor), first, integer_length);
p = first.add(integer_length);
if fraction_length > 0 {
*p = b'.';
p = p.add(1);
ptr::copy_nonoverlapping(buffer.add(initial_position), p, fraction_length);
p = p.add(fraction_length);
} else {
ptr::copy_nonoverlapping(b".0".as_ptr(), p, 2);
p = p.add(2);
}
return p;
}
}
#[inline(always)]
pub(crate) unsafe extern "C" fn float_radix(f: f32, radix: u32, first: *mut u8)
-> *mut u8
{
double_radix(f as f64, radix, first)
}
#[inline(always)]
pub(crate) unsafe extern "C" fn double_radix(value: f64, radix:u32, first: *mut u8)
-> *mut u8
{
ftoa_naive(value, radix, first)
}