#![no_std]
#![doc(html_root_url = "https://docs.rs/dragonbox/0.1.12")]
#![allow(unsafe_op_in_unsafe_fn, unused_parens)]
#![cfg_attr(dragonbox_dead_code_workaround, allow(dead_code))]
#![allow(
clippy::assertions_on_constants,
clippy::bool_to_int_with_if,
clippy::cast_possible_truncation,
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
clippy::comparison_chain,
clippy::doc_markdown,
clippy::eq_op,
clippy::expl_impl_clone_on_copy,
clippy::if_not_else,
clippy::items_after_statements,
clippy::must_use_candidate,
clippy::needless_bitwise_bool,
clippy::needless_doctest_main,
clippy::never_loop,
clippy::similar_names,
clippy::too_many_lines,
clippy::unreadable_literal,
clippy::verbose_bit_mask
)]
mod buffer;
mod cache;
mod div;
mod log;
mod policy;
mod to_chars;
mod wuint;
use crate::buffer::Sealed;
use crate::cache::EntryTypeExt as _;
use core::mem::MaybeUninit;
pub struct Buffer {
bytes: [MaybeUninit<u8>; to_chars::MAX_OUTPUT_STRING_LENGTH],
}
pub trait Float: Sealed {}
const TOTAL_BITS: usize = 64;
const SIGNIFICAND_BITS: usize = 52;
const EXPONENT_BITS: usize = 11;
const MIN_EXPONENT: i32 = -1022;
const MAX_EXPONENT: i32 = 1023;
const EXPONENT_BIAS: i32 = -1023;
const DECIMAL_SIGNIFICAND_DIGITS: usize = 17;
const DECIMAL_EXPONENT_DIGITS: usize = 3;
type CarrierUint = u64;
const CARRIER_BITS: usize = 64;
type ExponentInt = i32;
const fn extract_exponent_bits(u: CarrierUint) -> ExponentInt {
(u >> SIGNIFICAND_BITS) as ExponentInt & (((1 as ExponentInt) << EXPONENT_BITS) - 1)
}
const fn remove_exponent_bits(u: CarrierUint) -> CarrierUint {
u & !(((1 << EXPONENT_BITS) - 1) << SIGNIFICAND_BITS)
}
const fn remove_sign_bit_and_shift(u: CarrierUint) -> CarrierUint {
(u << 1) & ((((1 << (TOTAL_BITS - 1)) - 1) << 1) | 1)
}
const fn is_nonzero(u: CarrierUint) -> bool {
(u & ((1 << (SIGNIFICAND_BITS + EXPONENT_BITS)) - 1)) != 0
}
const fn is_positive(u: CarrierUint) -> bool {
u < (1 << (SIGNIFICAND_BITS + EXPONENT_BITS))
}
const fn is_negative(u: CarrierUint) -> bool {
!is_positive(u)
}
const fn has_even_significand_bits(s: CarrierUint) -> bool {
s % 2 == 0
}
const fn compute_power32<const K: u32>(a: u32) -> u32 {
let mut p = 1;
let mut i = 0;
while i < K {
p *= a;
i += 1;
}
p
}
const fn compute_power64<const K: u32>(a: u64) -> u64 {
let mut p = 1;
let mut i = 0;
while i < K {
p *= a;
i += 1;
}
p
}
const fn count_factors<const A: usize>(mut n: usize) -> u32 {
const {
assert!(A > 1);
}
let mut c = 0;
while n % A == 0 {
n /= A;
c += 1;
}
c
}
struct Decimal {
significand: u64,
exponent: i32,
}
const KAPPA: u32 = (log::floor_log10_pow2::<
{ log::FLOOR_LOG10_POW2_MIN_EXPONENT },
{ log::FLOOR_LOG10_POW2_MAX_EXPONENT },
>(CARRIER_BITS as i32 - SIGNIFICAND_BITS as i32 - 2)
- 1) as u32;
const _: () = assert!(
CARRIER_BITS as i32
>= SIGNIFICAND_BITS as i32
+ 2
+ log::floor_log2_pow10::<
{ log::FLOOR_LOG2_POW10_MIN_EXPONENT },
{ log::FLOOR_LOG2_POW10_MAX_EXPONENT },
>(KAPPA as i32 + 1),
);
const fn min(x: i32, y: i32) -> i32 {
if x < y {
x
} else {
y
}
}
const fn max(x: i32, y: i32) -> i32 {
if x > y {
x
} else {
y
}
}
const MIN_K: i32 = min(
-log::floor_log10_pow2_minus_log10_4_over_3::<
{ log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MIN_EXPONENT },
{ log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MAX_EXPONENT },
>(MAX_EXPONENT - SIGNIFICAND_BITS as i32),
-log::floor_log10_pow2::<
{ log::FLOOR_LOG10_POW2_MIN_EXPONENT },
{ log::FLOOR_LOG10_POW2_MAX_EXPONENT },
>(MAX_EXPONENT - SIGNIFICAND_BITS as i32)
+ KAPPA as i32,
);
const _: () = assert!(MIN_K >= cache::MIN_K);
const MAX_K: i32 = max(
-log::floor_log10_pow2_minus_log10_4_over_3::<
{ log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MIN_EXPONENT },
{ log::FLOOR_LOG10_POW2_MINUS_LOG10_4_OVER_3_MAX_EXPONENT },
>(MIN_EXPONENT - SIGNIFICAND_BITS as i32 ),
-log::floor_log10_pow2::<
{ log::FLOOR_LOG10_POW2_MIN_EXPONENT },
{ log::FLOOR_LOG10_POW2_MAX_EXPONENT },
>(MIN_EXPONENT - SIGNIFICAND_BITS as i32)
+ KAPPA as i32,
);
const _: () = assert!(MAX_K <= cache::MAX_K);
struct ComputeMulResult {
integer_part: CarrierUint,
is_integer: bool,
}
fn compute_mul(u: CarrierUint, cache: &cache::EntryType) -> ComputeMulResult {
let r = wuint::umul192_upper128(u, *cache);
ComputeMulResult {
integer_part: r.high(),
is_integer: r.low() == 0,
}
}
fn compute_delta(cache: &cache::EntryType, beta: i32) -> u32 {
(cache.high() >> ((CARRIER_BITS - 1) as i32 - beta)) as u32
}
struct ComputeMulParityResult {
parity: bool,
is_integer: bool,
}
fn compute_mul_parity(
two_f: CarrierUint,
cache: &cache::EntryType,
beta: i32,
) -> ComputeMulParityResult {
debug_assert!(beta >= 1);
debug_assert!(beta < 64);
let r = wuint::umul192_lower128(two_f, *cache);
ComputeMulParityResult {
parity: ((r.high() >> (64 - beta)) & 1) != 0,
is_integer: ((r.high() << beta) | (r.low() >> (64 - beta))) == 0,
}
}
fn compute_left_endpoint_for_shorter_interval_case(
cache: &cache::EntryType,
beta: i32,
) -> CarrierUint {
(cache.high() - (cache.high() >> (SIGNIFICAND_BITS + 2)))
>> ((CARRIER_BITS - SIGNIFICAND_BITS - 1) as i32 - beta)
}
fn compute_right_endpoint_for_shorter_interval_case(
cache: &cache::EntryType,
beta: i32,
) -> CarrierUint {
(cache.high() + (cache.high() >> (SIGNIFICAND_BITS + 1)))
>> ((CARRIER_BITS - SIGNIFICAND_BITS - 1) as i32 - beta)
}
fn compute_round_up_for_shorter_interval_case(cache: &cache::EntryType, beta: i32) -> CarrierUint {
(cache.high() >> ((CARRIER_BITS - SIGNIFICAND_BITS - 2) as i32 - beta)).div_ceil(2)
}
const fn floor_log2(mut n: u64) -> i32 {
let mut count = -1;
while n != 0 {
count += 1;
n >>= 1;
}
count
}
fn is_left_endpoint_integer_shorter_interval(exponent: i32) -> bool {
const CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_LOWER_THRESHOLD: i32 = 2;
const CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_UPPER_THRESHOLD: i32 = 2 + floor_log2(
compute_power64::<
{
count_factors::<5>((((1 as CarrierUint) << (SIGNIFICAND_BITS + 2)) - 1) as usize)
+ 1
},
>(10)
/ 3,
);
(CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_LOWER_THRESHOLD
..=CASE_SHORTER_INTERVAL_LEFT_ENDPOINT_UPPER_THRESHOLD)
.contains(&exponent)
}
fn compute_nearest(signed_significand_bits: CarrierUint, exponent_bits: ExponentInt) -> Decimal {
let mut two_fc = remove_sign_bit_and_shift(signed_significand_bits);
let mut binary_exponent = exponent_bits;
if binary_exponent != 0 {
binary_exponent += EXPONENT_BIAS - SIGNIFICAND_BITS as i32;
if two_fc == 0 {
let minus_k = log::floor_log10_pow2_minus_log10_4_over_3::<
{ MIN_EXPONENT - SIGNIFICAND_BITS as i32 },
{ MAX_EXPONENT - SIGNIFICAND_BITS as i32 },
>(binary_exponent);
let beta = binary_exponent + log::floor_log2_pow10::<MIN_K, MAX_K>(-minus_k);
let cache = unsafe { cache::get(-minus_k) };
let mut xi = compute_left_endpoint_for_shorter_interval_case(&cache, beta);
let zi = compute_right_endpoint_for_shorter_interval_case(&cache, beta);
if !is_left_endpoint_integer_shorter_interval(binary_exponent) {
xi += 1;
}
let mut decimal_significand = div::divide_by_pow10::<
1,
{ ((((1 << (SIGNIFICAND_BITS + 1)) + 1) / 3) + 1) * 20 },
>(zi);
if decimal_significand * 10 >= xi {
return Decimal {
significand: decimal_significand,
exponent: minus_k + 1,
};
}
decimal_significand = compute_round_up_for_shorter_interval_case(&cache, beta);
const SHORTER_INTERVAL_TIE_LOWER_THRESHOLD: i32 =
-log::floor_log5_pow2_minus_log5_3(SIGNIFICAND_BITS as i32 + 4)
- 2
- SIGNIFICAND_BITS as i32;
const SHORTER_INTERVAL_TIE_UPPER_THRESHOLD: i32 =
-log::floor_log5_pow2(SIGNIFICAND_BITS as i32 + 2) - 2 - SIGNIFICAND_BITS as i32;
if policy::prefer_round_down(decimal_significand)
&& binary_exponent >= SHORTER_INTERVAL_TIE_LOWER_THRESHOLD
&& binary_exponent <= SHORTER_INTERVAL_TIE_UPPER_THRESHOLD
{
decimal_significand -= 1;
} else if decimal_significand < xi {
decimal_significand += 1;
}
return Decimal {
significand: decimal_significand,
exponent: minus_k,
};
}
two_fc |= 1 << (SIGNIFICAND_BITS + 1);
}
else {
binary_exponent = MIN_EXPONENT - SIGNIFICAND_BITS as i32;
}
let has_even_significand_bits = has_even_significand_bits(signed_significand_bits);
let minus_k = log::floor_log10_pow2::<
{ MIN_EXPONENT - SIGNIFICAND_BITS as i32 },
{ MAX_EXPONENT - SIGNIFICAND_BITS as i32 },
>(binary_exponent)
- KAPPA as i32;
let cache = unsafe { cache::get(-minus_k) };
let beta = binary_exponent + log::floor_log2_pow10::<MIN_K, MAX_K>(-minus_k);
let deltai = compute_delta(&cache, beta);
let z_result = compute_mul((two_fc | 1) << beta, &cache);
const BIG_DIVISOR: u32 = compute_power32::<{ KAPPA + 1 }>(10);
const SMALL_DIVISOR: u32 = compute_power32::<KAPPA>(10);
let mut decimal_significand = div::divide_by_pow10::<
{ KAPPA + 1 },
{ (1 << (SIGNIFICAND_BITS + 1)) * BIG_DIVISOR as u64 - 1 },
>(z_result.integer_part);
let mut r = (z_result.integer_part - u64::from(BIG_DIVISOR) * decimal_significand) as u32;
loop {
if r < deltai {
if (r | u32::from(!z_result.is_integer) | u32::from(has_even_significand_bits)) == 0 {
decimal_significand -= 1;
r = BIG_DIVISOR;
break;
}
} else if r > deltai {
break;
} else {
let x_result = compute_mul_parity(two_fc - 1, &cache, beta);
if !(x_result.parity | (x_result.is_integer & has_even_significand_bits)) {
break;
}
}
return Decimal {
significand: decimal_significand,
exponent: minus_k + KAPPA as i32 + 1,
};
}
decimal_significand *= 10;
let mut dist = r - (deltai / 2) + (SMALL_DIVISOR / 2);
let approx_y_parity = ((dist ^ (SMALL_DIVISOR / 2)) & 1) != 0;
let divisible_by_small_divisor = div::check_divisibility_and_divide_by_pow10(&mut dist);
decimal_significand += CarrierUint::from(dist);
if divisible_by_small_divisor {
let y_result = compute_mul_parity(two_fc, &cache, beta);
if y_result.parity != approx_y_parity {
decimal_significand -= 1;
} else {
if policy::prefer_round_down(decimal_significand) & y_result.is_integer {
decimal_significand -= 1;
}
}
}
Decimal {
significand: decimal_significand,
exponent: minus_k + KAPPA as i32,
}
}
fn to_decimal(x: f64) -> Decimal {
let br = x.to_bits();
let exponent_bits = extract_exponent_bits(br);
let s = remove_exponent_bits(br);
compute_nearest(s, exponent_bits)
}