#![cfg(feature = "power-of-two")]
#![doc(hidden)]
use crate::binary::{
calculate_shl,
fast_ceildiv,
fast_log2,
truncate_and_round,
write_float_negative_exponent,
write_float_positive_exponent,
};
use crate::options::Options;
use crate::shared;
use lexical_util::algorithm::rtrim_char_count;
use lexical_util::constants::{FormattedSize, BUFFER_SIZE};
use lexical_util::format::NumberFormat;
use lexical_util::num::{Float, Integer};
use lexical_write_integer::write::WriteInteger;
pub unsafe fn write_float<F: Float, const FORMAT: u128>(
float: F,
bytes: &mut [u8],
options: &Options,
) -> usize
where
<F as Float>::Unsigned: WriteInteger + FormattedSize,
{
let format = NumberFormat::<{ FORMAT }> {};
assert!(format.is_valid());
debug_assert!(!float.is_special());
debug_assert!(float >= F::ZERO);
debug_assert!(matches!(
(format.radix(), format.exponent_base()),
(4, 2) | (8, 2) | (16, 2) | (32, 2) | (16, 4)
));
let mantissa = float.mantissa();
let radix = format.mantissa_radix();
let (mantissa, mantissa_bits) = truncate_and_round(mantissa, radix, options);
let exp = float.exponent();
let mut sci_exp = exp + mantissa_bits as i32 - 1;
if mantissa == <F as Float>::Unsigned::ZERO {
sci_exp = 0;
}
write_float!(
FORMAT,
sci_exp,
options,
write_float_scientific,
write_float_positive_exponent,
write_float_negative_exponent,
generic => _,
args => mantissa, exp, sci_exp, bytes, options,
)
}
#[inline]
pub unsafe fn write_float_scientific<M, const FORMAT: u128>(
mantissa: M,
exp: i32,
sci_exp: i32,
bytes: &mut [u8],
options: &Options,
) -> usize
where
M: WriteInteger + FormattedSize,
{
assert!(M::FORMATTED_SIZE < BUFFER_SIZE - 2);
debug_assert!(bytes.len() >= BUFFER_SIZE);
let format = NumberFormat::<{ FORMAT }> {};
let bits_per_digit = fast_log2(format.mantissa_radix());
let bits_per_base = fast_log2(format.exponent_base());
let decimal_point = options.decimal_point();
let shl = calculate_shl(exp, bits_per_digit);
let value = mantissa << shl;
let digit_count = unsafe {
let count = value.write_mantissa::<M, FORMAT>(&mut index_unchecked_mut!(bytes[1..]));
index_unchecked_mut!(bytes[0] = bytes[1]);
index_unchecked_mut!(bytes[1]) = decimal_point;
let zeros = rtrim_char_count(&index_unchecked!(bytes[2..count + 1]), b'0');
count - zeros
};
let mut cursor = digit_count + 1;
let exact_count = shared::min_exact_digits(digit_count, options);
if !format.no_exponent_without_fraction() && cursor == 2 && options.trim_floats() {
cursor -= 1;
} else if exact_count < 2 {
unsafe { index_unchecked_mut!(bytes[cursor]) = b'0' };
cursor += 1;
} else if exact_count > digit_count {
let digits_end = exact_count + 1;
unsafe {
slice_fill_unchecked!(index_unchecked_mut!(bytes[cursor..digits_end]), b'0');
}
cursor = digits_end;
}
let scaled_sci_exp = scale_sci_exp(sci_exp, bits_per_digit, bits_per_base);
unsafe {
shared::write_exponent::<FORMAT>(bytes, &mut cursor, scaled_sci_exp, options.exponent())
};
cursor
}
#[inline(always)]
pub fn scale_sci_exp(sci_exp: i32, bits_per_digit: i32, bits_per_base: i32) -> i32 {
if sci_exp < 0 {
let neg_sci_exp = sci_exp.wrapping_neg();
let floor = fast_ceildiv(neg_sci_exp, bits_per_digit);
(floor * bits_per_digit / bits_per_base).wrapping_neg()
} else {
let floor = sci_exp / bits_per_digit;
floor * bits_per_digit / bits_per_base
}
}