Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
@@ -0,0 +1,750 @@
#![cfg(not(feature = "compact"))]
use core::num;
use lexical_util::constants::BUFFER_SIZE;
use lexical_util::format::NumberFormatBuilder;
use lexical_util::num::Float;
use lexical_write_float::algorithm::DragonboxFloat;
use lexical_write_float::float::{ExtendedFloat80, RawFloat};
use lexical_write_float::{algorithm, Options, RoundMode};
const DECIMAL: u128 = NumberFormatBuilder::decimal();
fn floor_shift(integer: u32, fraction: u64, shift: i32) -> i32 {
((integer << shift) | (fraction >> (64 - shift)) as u32) as i32
}
fn dragonbox_log5_2(q: i32) -> i32 {
let c = floor_shift(0, 0x6e40d1a4143dcb94, 20);
let s = floor_shift(0, 0, 20);
(q * c - s) >> 20
}
fn dragonbox_log10_2(q: i32) -> i32 {
let c = floor_shift(0, 0x4d104d427de7fbcc, 22);
let s = floor_shift(0, 0, 22);
(q * c - s) >> 22
}
fn dragonbox_log2_10(q: i32) -> i32 {
let c = floor_shift(3, 0x5269e12f346e2bf9, 19);
let s = floor_shift(0, 0, 19);
(q * c - s) >> 19
}
fn dragonbox_log5_2_sub_log5_3(q: i32) -> i32 {
let c = floor_shift(0, 0x6e40d1a4143dcb94, 20);
let s = floor_shift(0, 0xaebf47915d443b24, 20);
(q * c - s) >> 20
}
fn dragonbox_log10_2_sub_log10_4_div3(q: i32) -> i32 {
let c = floor_shift(0, 0x4d104d427de7fbcc, 22);
let s = floor_shift(0, 0x1ffbfc2bbc780375, 22);
(q * c - s) >> 22
}
#[test]
fn floor_log5_pow2_test() {
for q in -1492i32..=1492 {
let actual = algorithm::floor_log5_pow2(q);
let expected = dragonbox_log5_2(q);
assert_eq!(actual, expected);
}
}
#[test]
fn floor_log10_pow2_test() {
for q in -1700i32..=1700 {
let actual = algorithm::floor_log10_pow2(q);
let expected = dragonbox_log10_2(q);
assert_eq!(actual, expected);
}
}
#[test]
fn floor_log2_pow10_test() {
for q in -1233i32..=1233 {
let actual = algorithm::floor_log2_pow10(q);
let expected = dragonbox_log2_10(q);
assert_eq!(actual, expected);
}
}
#[test]
fn floor_log5_pow2_minus_log5_3_test() {
for q in -2427i32..=2427 {
let actual = algorithm::floor_log5_pow2_minus_log5_3(q);
let expected = dragonbox_log5_2_sub_log5_3(q);
assert_eq!(actual, expected);
}
}
#[test]
fn floor_log10_pow2_minus_log10_4_over_3_test() {
for q in -1700i32..=1700 {
let actual = algorithm::floor_log10_pow2_minus_log10_4_over_3(q);
let expected = dragonbox_log10_2_sub_log10_4_div3(q);
assert_eq!(actual, expected);
}
}
#[test]
fn issue84_test() {
let (hi, lo) =
algorithm::umul192_lower128(15966911296221875, 0xcccccccccccccccc, 0xcccccccccccccccd);
assert_eq!(hi, 0);
assert_eq!(lo, 3193382259244375);
}
#[test]
fn pow32_test() {
assert_eq!(algorithm::pow32(10, 1), 10);
assert_eq!(algorithm::pow32(10, 2), 100);
}
#[test]
fn pow64_test() {
assert_eq!(algorithm::pow64(10, 1), 10);
assert_eq!(algorithm::pow64(10, 2), 100);
}
#[test]
fn count_factors_test() {
assert_eq!(algorithm::count_factors(5, 25), 2);
assert_eq!(algorithm::count_factors(5, 30), 1);
assert_eq!(algorithm::count_factors(5, 125), 3);
assert_eq!(algorithm::count_factors(5, 126), 0);
}
#[test]
fn floor_log2_test() {
assert_eq!(algorithm::floor_log2(25), 4);
assert_eq!(algorithm::floor_log2(30), 4);
assert_eq!(algorithm::floor_log2(125), 6);
assert_eq!(algorithm::floor_log2(126), 6);
assert_eq!(algorithm::floor_log2(128), 7);
}
fn to_decimal_f32(float: f32) -> (u64, i32) {
let fp = algorithm::to_decimal(float);
(fp.mant, fp.exp)
}
fn to_decimal_f64(float: f64) -> (u64, i32) {
let fp = algorithm::to_decimal(float);
(fp.mant, fp.exp)
}
#[test]
fn to_decimal_test() {
assert_eq!(to_decimal_f32(0.0), (0, 0));
assert_eq!(to_decimal_f32(0.5), (5, -1));
assert_eq!(to_decimal_f32(1.0), (1, 0));
assert_eq!(to_decimal_f32(1.5), (15, -1));
assert_eq!(to_decimal_f32(1.23456), (123456, -5));
assert_eq!(to_decimal_f32(2.3786281e+38), (23786281, 31));
assert_eq!(to_decimal_f32(2147481600.0), (21474816, 2));
assert_eq!(to_decimal_f32(2147483600.0), (21474836, 2));
assert_eq!(to_decimal_f32(2762159900.0), (27621599, 2));
assert_eq!(to_decimal_f32(77371252000000000000000000.0), (77371252, 18));
assert_eq!(to_decimal_f64(0.0), (0, 0));
assert_eq!(to_decimal_f64(0.5), (5, -1));
assert_eq!(to_decimal_f64(1.0), (1, 0));
assert_eq!(to_decimal_f64(1.5), (15, -1));
assert_eq!(to_decimal_f64(1.23456), (123456, -5));
assert_eq!(to_decimal_f64(2.2250738585072014e-308), (22250738585072014, -324));
assert_eq!(to_decimal_f64(1.7976931348623157e+308), (17976931348623157, 292));
}
fn compute_nearest_shorter(float: f64) -> (u64, i32) {
let fp = algorithm::compute_nearest_shorter(float);
(fp.mant, fp.exp)
}
#[test]
fn compute_nearest_shorter_test() {
assert_eq!(compute_nearest_shorter(0.5), (5, -1));
assert_eq!(compute_nearest_shorter(1.0), (1, 0));
assert_eq!(compute_nearest_shorter(2.0), (2, 0));
}
fn compute_nearest_normal(float: f64) -> (u64, i32) {
let fp = algorithm::compute_nearest_normal(float);
(fp.mant, fp.exp)
}
#[test]
fn compute_nearest_normal_test() {
assert_eq!(compute_nearest_normal(1.23456), (123456, -5));
assert_eq!(compute_nearest_normal(13.9999999999999982236431606), (13999999999999998, -15));
}
fn compute_left_closed_directed(float: f64) -> (u64, i32) {
let fp = algorithm::compute_left_closed_directed(float);
(fp.mant, fp.exp)
}
#[test]
fn compute_left_closed_directed_test() {
assert_eq!(compute_left_closed_directed(1.23456), (12345600000000002, -16));
assert_eq!(
compute_left_closed_directed(13.9999999999999982236431606),
(13999999999999999, -15)
);
}
fn compute_right_closed_directed(float: f64) -> (u64, i32) {
// Assume we do not have a shorter case.
let bits = float.to_bits();
let mantissa_bits = bits & f64::MANTISSA_MASK;
assert!(mantissa_bits != 0);
let fp = algorithm::compute_right_closed_directed(float, false);
(fp.mant, fp.exp)
}
#[test]
fn compute_right_closed_directed_test() {
assert_eq!(compute_right_closed_directed(1.23456), (123456, -5));
assert_eq!(
compute_right_closed_directed(13.9999999999999982236431606),
(13999999999999982, -15)
);
}
fn write_digits_f32(buffer: &mut [u8], value: u64, expected: &str) {
let count = f32::write_digits(buffer, value);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_digits_f32_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
write_digits_f32(&mut buffer, 0, "0");
write_digits_f32(&mut buffer, 1, "1");
write_digits_f32(&mut buffer, 11, "11");
write_digits_f32(&mut buffer, 23, "23");
write_digits_f32(&mut buffer, 23786281, "23786281");
write_digits_f32(&mut buffer, 4294967295, "4294967295");
}
fn write_digits_f64(buffer: &mut [u8], value: u64, expected: &str) {
let count = f64::write_digits(buffer, value);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_digits_f64_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
write_digits_f64(&mut buffer, 0, "0");
write_digits_f64(&mut buffer, 1, "1");
write_digits_f64(&mut buffer, 11, "11");
write_digits_f64(&mut buffer, 23, "23");
write_digits_f64(&mut buffer, 4294967295, "4294967295");
write_digits_f64(&mut buffer, 4294967296, "4294967296");
}
fn write_float_scientific(mant: u64, exp: i32, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let fp = ExtendedFloat80 {
mant,
exp,
};
let digit_count = f64::digit_count(fp.mant);
let sci_exp = fp.exp + digit_count as i32 - 1;
let count =
algorithm::write_float_scientific::<f64, DECIMAL>(&mut buffer, fp, sci_exp, &options);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_scientific_test() {
const OPTS1: Options = Options::new();
write_float_scientific(1, 0, &OPTS1, "1.0e0");
write_float_scientific(1, 3, &OPTS1, "1.0e3");
write_float_scientific(1, -12, &OPTS1, "1.0e-12");
write_float_scientific(999999999999999, -15, &OPTS1, "9.99999999999999e-1");
write_float_scientific(999999999999999, -14, &OPTS1, "9.99999999999999e0");
write_float_scientific(999999999999999, -16, &OPTS1, "9.99999999999999e-2");
write_float_scientific(17976931348623157, 292, &OPTS1, "1.7976931348623157e308");
write_float_scientific(22250738585072014, -324, &OPTS1, "2.2250738585072014e-308");
const OPTS2: Options =
Options::builder().min_significant_digits(num::NonZeroUsize::new(50)).build_strict();
write_float_scientific(1, 0, &OPTS2, "1.0000000000000000000000000000000000000000000000000e0");
write_float_scientific(1, 3, &OPTS2, "1.0000000000000000000000000000000000000000000000000e3");
write_float_scientific(
1,
-12,
&OPTS2,
"1.0000000000000000000000000000000000000000000000000e-12",
);
write_float_scientific(
999999999999999,
-15,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000e-1",
);
write_float_scientific(
999999999999999,
-14,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000e0",
);
write_float_scientific(
999999999999999,
-16,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000e-2",
);
write_float_scientific(
17976931348623157,
292,
&OPTS2,
"1.7976931348623157000000000000000000000000000000000e308",
);
write_float_scientific(
22250738585072014,
-324,
&OPTS2,
"2.2250738585072014000000000000000000000000000000000e-308",
);
const OPTS3: Options =
Options::builder().max_significant_digits(num::NonZeroUsize::new(5)).build_strict();
write_float_scientific(1, 0, &OPTS3, "1.0e0");
write_float_scientific(1, 3, &OPTS3, "1.0e3");
write_float_scientific(1, -12, &OPTS3, "1.0e-12");
write_float_scientific(999999999999999, -15, &OPTS3, "1.0e0");
write_float_scientific(999999999999999, -14, &OPTS3, "1.0e1");
write_float_scientific(999999999999999, -16, &OPTS3, "1.0e-1");
write_float_scientific(17976931348623157, 292, &OPTS3, "1.7977e308");
write_float_scientific(22250738585072014, -324, &OPTS3, "2.2251e-308");
const OPTS4: Options = Options::builder().trim_floats(true).build_strict();
write_float_scientific(1, 0, &OPTS4, "1e0");
write_float_scientific(1, 3, &OPTS4, "1e3");
write_float_scientific(1, -12, &OPTS4, "1e-12");
write_float_scientific(999999999999999, -15, &OPTS4, "9.99999999999999e-1");
write_float_scientific(999999999999999, -14, &OPTS4, "9.99999999999999e0");
write_float_scientific(999999999999999, -16, &OPTS4, "9.99999999999999e-2");
write_float_scientific(17976931348623157, 292, &OPTS4, "1.7976931348623157e308");
write_float_scientific(22250738585072014, -324, &OPTS4, "2.2250738585072014e-308");
}
fn write_float_positive_exponent(mant: u64, exp: i32, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; 512];
let fp = ExtendedFloat80 {
mant,
exp,
};
let digit_count = f64::digit_count(fp.mant);
let sci_exp = fp.exp + digit_count as i32 - 1;
let count = algorithm::write_float_positive_exponent::<f64, DECIMAL>(
&mut buffer,
fp,
sci_exp,
&options,
);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_positive_exponent_test() {
const OPTS1: Options = Options::new();
write_float_positive_exponent(1, 0, &OPTS1, "1.0");
write_float_positive_exponent(1, 3, &OPTS1, "1000.0");
write_float_positive_exponent(1, 12, &OPTS1, "1000000000000.0");
write_float_positive_exponent(999999999999999, -14, &OPTS1, "9.99999999999999");
write_float_positive_exponent(999999999999999, -13, &OPTS1, "99.9999999999999");
write_float_positive_exponent(999999999999999, -12, &OPTS1, "999.999999999999");
write_float_positive_exponent(17976931348623157, 292, &OPTS1, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0");
const OPTS2: Options =
Options::builder().min_significant_digits(num::NonZeroUsize::new(50)).build_strict();
write_float_positive_exponent(
1,
0,
&OPTS2,
"1.0000000000000000000000000000000000000000000000000",
);
write_float_positive_exponent(
1,
3,
&OPTS2,
"1000.0000000000000000000000000000000000000000000000",
);
write_float_positive_exponent(
1,
12,
&OPTS2,
"1000000000000.0000000000000000000000000000000000000",
);
write_float_positive_exponent(
999999999999999,
-14,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000",
);
write_float_positive_exponent(
999999999999999,
-13,
&OPTS2,
"99.999999999999900000000000000000000000000000000000",
);
write_float_positive_exponent(
999999999999999,
-12,
&OPTS2,
"999.99999999999900000000000000000000000000000000000",
);
write_float_positive_exponent(17976931348623157, 292, &OPTS2, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0");
const OPTS3: Options =
Options::builder().max_significant_digits(num::NonZeroUsize::new(5)).build_strict();
write_float_positive_exponent(1, 0, &OPTS3, "1.0");
write_float_positive_exponent(1, 3, &OPTS3, "1000.0");
write_float_positive_exponent(1, 12, &OPTS3, "1000000000000.0");
write_float_positive_exponent(999999999999999, -14, &OPTS3, "10.0");
write_float_positive_exponent(999999999999999, -13, &OPTS3, "100.0");
write_float_positive_exponent(999999999999999, -12, &OPTS3, "1000.0");
write_float_positive_exponent(17976931348623157, 292, &OPTS3, "179770000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0");
const OPTS4: Options = Options::builder().trim_floats(true).build_strict();
write_float_positive_exponent(1, 0, &OPTS4, "1");
write_float_positive_exponent(1, 3, &OPTS4, "1000");
write_float_positive_exponent(1, 12, &OPTS4, "1000000000000");
write_float_positive_exponent(999999999999999, -14, &OPTS4, "9.99999999999999");
write_float_positive_exponent(999999999999999, -13, &OPTS4, "99.9999999999999");
write_float_positive_exponent(999999999999999, -12, &OPTS4, "999.999999999999");
write_float_positive_exponent(17976931348623157, 292, &OPTS4, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
fn write_float_negative_exponent(mant: u64, exp: i32, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; 512];
let fp = ExtendedFloat80 {
mant,
exp,
};
let digit_count = f64::digit_count(fp.mant);
let sci_exp = fp.exp + digit_count as i32 - 1;
let count = algorithm::write_float_negative_exponent::<f64, DECIMAL>(
&mut buffer,
fp,
sci_exp,
&options,
);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_negative_exponent_test() {
const OPTS1: Options = Options::new();
write_float_negative_exponent(1, -1, &OPTS1, "0.1");
write_float_negative_exponent(1, -3, &OPTS1, "0.001");
write_float_negative_exponent(1, -12, &OPTS1, "0.000000000001");
write_float_negative_exponent(999999999999999, -17, &OPTS1, "0.00999999999999999");
write_float_negative_exponent(999999999999999, -16, &OPTS1, "0.0999999999999999");
write_float_negative_exponent(999999999999999, -15, &OPTS1, "0.999999999999999");
write_float_negative_exponent(22250738585072014, -324, &OPTS1, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014");
const OPTS2: Options =
Options::builder().min_significant_digits(num::NonZeroUsize::new(50)).build_strict();
write_float_negative_exponent(
1,
-1,
&OPTS2,
"0.10000000000000000000000000000000000000000000000000",
);
write_float_negative_exponent(
1,
-3,
&OPTS2,
"0.0010000000000000000000000000000000000000000000000000",
);
write_float_negative_exponent(
1,
-12,
&OPTS2,
"0.0000000000010000000000000000000000000000000000000000000000000",
);
write_float_negative_exponent(
999999999999999,
-17,
&OPTS2,
"0.0099999999999999900000000000000000000000000000000000",
);
write_float_negative_exponent(
999999999999999,
-16,
&OPTS2,
"0.099999999999999900000000000000000000000000000000000",
);
write_float_negative_exponent(
999999999999999,
-15,
&OPTS2,
"0.99999999999999900000000000000000000000000000000000",
);
write_float_negative_exponent(22250738585072014, -324, &OPTS2, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014000000000000000000000000000000000");
const OPTS3: Options =
Options::builder().max_significant_digits(num::NonZeroUsize::new(5)).build_strict();
write_float_negative_exponent(1, -1, &OPTS3, "0.1");
write_float_negative_exponent(1, -3, &OPTS3, "0.001");
write_float_negative_exponent(1, -12, &OPTS3, "0.000000000001");
write_float_negative_exponent(999999999999999, -17, &OPTS3, "0.01");
write_float_negative_exponent(999999999999999, -16, &OPTS3, "0.1");
write_float_negative_exponent(999999999999999, -15, &OPTS3, "1.0");
write_float_negative_exponent(22250738585072014, -324, &OPTS3, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022251");
const OPTS4: Options = Options::builder().trim_floats(true).build_strict();
write_float_negative_exponent(1, -1, &OPTS4, "0.1");
write_float_negative_exponent(1, -3, &OPTS4, "0.001");
write_float_negative_exponent(1, -12, &OPTS4, "0.000000000001");
write_float_negative_exponent(999999999999999, -17, &OPTS4, "0.00999999999999999");
write_float_negative_exponent(999999999999999, -16, &OPTS4, "0.0999999999999999");
write_float_negative_exponent(999999999999999, -15, &OPTS4, "0.999999999999999");
write_float_negative_exponent(22250738585072014, -324, &OPTS4, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014");
}
// Test data for roundtrips.
const F32_DATA: [f32; 31] = [
0.,
0.1,
1.,
1.1,
12.,
12.1,
123.,
123.1,
1234.,
1234.1,
12345.,
12345.1,
123456.,
123456.1,
1234567.,
1234567.1,
12345678.,
12345678.1,
123456789.,
123456789.1,
123456789.12,
123456789.123,
123456789.1234,
123456789.12345,
1.2345678912345e8,
1.2345e+8,
1.2345e+11,
1.2345e+38,
1.2345e-8,
1.2345e-11,
1.2345e-38,
];
const F64_DATA: [f64; 33] = [
0.,
0.1,
1.,
1.1,
12.,
12.1,
123.,
123.1,
1234.,
1234.1,
12345.,
12345.1,
123456.,
123456.1,
1234567.,
1234567.1,
12345678.,
12345678.1,
123456789.,
123456789.1,
123456789.12,
123456789.123,
123456789.1234,
123456789.12345,
1.2345678912345e8,
1.2345e+8,
1.2345e+11,
1.2345e+38,
1.2345e+308,
1.2345e-8,
1.2345e-11,
1.2345e-38,
1.2345e-299,
];
fn write_float<T: RawFloat, const FORMAT: u128>(f: T, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let count = algorithm::write_float::<_, FORMAT>(f, &mut buffer, options);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn f32_test() {
const OPTS1: Options = Options::builder().trim_floats(true).build_strict();
write_float::<_, DECIMAL>(0.0f32, &OPTS1, "0");
write_float::<_, DECIMAL>(1.0f32, &OPTS1, "1");
write_float::<_, DECIMAL>(10.0f32, &OPTS1, "10");
write_float::<_, DECIMAL>(10.0f32, &OPTS1, "10");
write_float::<_, DECIMAL>(1.2345678901234567890e0f32, &OPTS1, "1.2345679");
write_float::<_, DECIMAL>(1.2345678901234567890e1f32, &OPTS1, "12.345679");
write_float::<_, DECIMAL>(1.2345678901234567890e2f32, &OPTS1, "123.45679");
write_float::<_, DECIMAL>(1.2345678901234567890e3f32, &OPTS1, "1234.5679");
write_float::<_, DECIMAL>(2.3786281e+38f32, &OPTS1, "2.3786281e38");
const OPTS2: Options = Options::new();
write_float::<_, DECIMAL>(2.3786281e+38f32, &OPTS2, "2.3786281e38");
}
#[test]
fn f32_errors_test() {
// Errors discovered via quickcheck.
const OPTIONS: Options = Options::new();
write_float::<_, DECIMAL>(0.0f32, &OPTIONS, "0.0");
write_float::<_, DECIMAL>(1073741800.0f32, &OPTIONS, "1073741800.0");
write_float::<_, DECIMAL>(1610612700.0f32, &OPTIONS, "1610612700.0");
write_float::<_, DECIMAL>(1879048200.0f32, &OPTIONS, "1879048200.0");
write_float::<_, DECIMAL>(2013265900.0f32, &OPTIONS, "2013265900.0");
write_float::<_, DECIMAL>(2080374800.0f32, &OPTIONS, "2080374800.0");
write_float::<_, DECIMAL>(2113929200.0f32, &OPTIONS, "2113929200.0");
write_float::<_, DECIMAL>(2130706400.0f32, &OPTIONS, "2130706400.0");
write_float::<_, DECIMAL>(2139095000.0f32, &OPTIONS, "2139095000.0");
write_float::<_, DECIMAL>(2143289300.0f32, &OPTIONS, "2143289300.0");
write_float::<_, DECIMAL>(2145386500.0f32, &OPTIONS, "2145386500.0");
write_float::<_, DECIMAL>(2146435100.0f32, &OPTIONS, "2146435100.0");
write_float::<_, DECIMAL>(2146959400.0f32, &OPTIONS, "2146959400.0");
write_float::<_, DECIMAL>(2147221500.0f32, &OPTIONS, "2147221500.0");
write_float::<_, DECIMAL>(2147352600.0f32, &OPTIONS, "2147352600.0");
write_float::<_, DECIMAL>(2147418100.0f32, &OPTIONS, "2147418100.0");
write_float::<_, DECIMAL>(2147450900.0f32, &OPTIONS, "2147450900.0");
write_float::<_, DECIMAL>(2147467300.0f32, &OPTIONS, "2147467300.0");
write_float::<_, DECIMAL>(2147475500.0f32, &OPTIONS, "2147475500.0");
write_float::<_, DECIMAL>(2147479600.0f32, &OPTIONS, "2147479600.0");
write_float::<_, DECIMAL>(2147481600.0f32, &OPTIONS, "2147481600.0");
write_float::<_, DECIMAL>(2147482600.0f32, &OPTIONS, "2147482600.0");
write_float::<_, DECIMAL>(2147483100.0f32, &OPTIONS, "2147483100.0");
write_float::<_, DECIMAL>(2147483400.0f32, &OPTIONS, "2147483400.0");
write_float::<_, DECIMAL>(2147483500.0f32, &OPTIONS, "2147483500.0");
write_float::<_, DECIMAL>(2147483600.0f32, &OPTIONS, "2147483600.0");
}
#[test]
fn f32_roundtrip_test() {
let mut buffer: [u8; BUFFER_SIZE] = [b'\x00'; BUFFER_SIZE];
const OPTIONS: Options = Options::builder().build_strict();
for &float in F32_DATA.iter() {
let count = algorithm::write_float::<_, DECIMAL>(float, &mut buffer, &OPTIONS);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
let roundtrip = actual.parse::<f32>();
assert_eq!(roundtrip, Ok(float));
}
}
#[test]
fn f64_test() {
const TRIM: Options = Options::builder().trim_floats(true).build_strict();
write_float::<_, DECIMAL>(0.0f64, &TRIM, "0");
write_float::<_, DECIMAL>(1.0f64, &TRIM, "1");
write_float::<_, DECIMAL>(10.0f64, &TRIM, "10");
write_float::<_, DECIMAL>(10.0f64, &TRIM, "10");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &TRIM, "1.2345678901234567");
write_float::<_, DECIMAL>(1.2345678901234567890e1f64, &TRIM, "12.345678901234567");
write_float::<_, DECIMAL>(1.2345678901234567890e2f64, &TRIM, "123.45678901234568");
write_float::<_, DECIMAL>(1.2345678901234567890e3f64, &TRIM, "1234.567890123457");
write_float::<_, DECIMAL>(1.5f64, &TRIM, "1.5");
write_float::<_, DECIMAL>(1.0e-17f64, &TRIM, "1e-17");
write_float::<_, DECIMAL>(9.99999999999999e-16f64, &TRIM, "9.99999999999999e-16");
write_float::<_, DECIMAL>(9.99999999999999e-15f64, &TRIM, "9.99999999999999e-15");
write_float::<_, DECIMAL>(0.00999999999999999f64, &TRIM, "0.00999999999999999");
write_float::<_, DECIMAL>(0.0999999999999999f64, &TRIM, "0.0999999999999999");
write_float::<_, DECIMAL>(0.999999999999999f64, &TRIM, "0.999999999999999");
write_float::<_, DECIMAL>(9.99999999999999f64, &TRIM, "9.99999999999999");
write_float::<_, DECIMAL>(99.9999999999999f64, &TRIM, "99.9999999999999");
write_float::<_, DECIMAL>(999.999999999999f64, &TRIM, "999.999999999999");
write_float::<_, DECIMAL>(1000.0f64, &TRIM, "1000");
write_float::<_, DECIMAL>(1.7976931348623157e308f64, &TRIM, "1.7976931348623157e308");
write_float::<_, DECIMAL>(2.2250738585072014e-308f64, &TRIM, "2.2250738585072014e-308");
const MIN_DIGITS: Options = Options::builder()
.min_significant_digits(num::NonZeroUsize::new(50))
.trim_floats(true)
.build_strict();
write_float::<_, DECIMAL>(1.0e17f64, &MIN_DIGITS, "1e17");
write_float::<_, DECIMAL>(1.0e-17f64, &MIN_DIGITS, "1e-17");
write_float::<_, DECIMAL>(1000.0f64, &MIN_DIGITS, "1000");
write_float::<_, DECIMAL>(
9.99999999999999e16f64,
&MIN_DIGITS,
"9.9999999999999900000000000000000000000000000000000e16",
);
write_float::<_, DECIMAL>(
9.99999999999999e-16f64,
&MIN_DIGITS,
"9.9999999999999900000000000000000000000000000000000e-16",
);
const TRUNCATE: Options = Options::builder()
.max_significant_digits(num::NonZeroUsize::new(4))
.round_mode(RoundMode::Truncate)
.build_strict();
const ROUND: Options = Options::builder()
.max_significant_digits(num::NonZeroUsize::new(4))
.round_mode(RoundMode::Round)
.build_strict();
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &TRUNCATE, "1.234");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &ROUND, "1.235");
write_float::<_, DECIMAL>(1.2345678901234567890e1f64, &TRUNCATE, "12.34");
write_float::<_, DECIMAL>(1.2345678901234567890e1f64, &ROUND, "12.35");
write_float::<_, DECIMAL>(1.2345678901234567890e2f64, &TRUNCATE, "123.4");
write_float::<_, DECIMAL>(1.2345678901234567890e2f64, &ROUND, "123.5");
write_float::<_, DECIMAL>(1.2345678901234567890e3f64, &TRUNCATE, "1234.0");
write_float::<_, DECIMAL>(1.2345678901234567890e3f64, &ROUND, "1235.0");
}
#[test]
fn f64_roundtrip_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
const OPTIONS: Options = Options::builder().build_strict();
for &float in F64_DATA.iter() {
let count = algorithm::write_float::<_, DECIMAL>(float, &mut buffer, &OPTIONS);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
let roundtrip = actual.parse::<f64>();
assert_eq!(roundtrip, Ok(float));
}
}
#[test]
fn is_endpoint_test() {
assert_eq!(algorithm::is_endpoint(5, 2, 10), true);
assert_eq!(algorithm::is_endpoint(5, 6, 10), false);
}
#[test]
fn is_right_endpoint_test() {
assert_eq!(algorithm::is_right_endpoint::<f64>(1), true);
assert_eq!(algorithm::is_right_endpoint::<f64>(2), true);
assert_eq!(algorithm::is_right_endpoint::<f64>(3), true);
assert_eq!(algorithm::is_right_endpoint::<f64>(4), false);
}
#[test]
fn is_left_endpoint_test() {
assert_eq!(algorithm::is_left_endpoint::<f64>(1), false);
assert_eq!(algorithm::is_left_endpoint::<f64>(2), true);
assert_eq!(algorithm::is_left_endpoint::<f64>(3), true);
assert_eq!(algorithm::is_left_endpoint::<f64>(4), false);
}
@@ -0,0 +1,80 @@
use lexical_util::constants::BUFFER_SIZE;
use lexical_util::format::STANDARD;
use lexical_write_float::{Options, ToLexical, ToLexicalWithOptions};
#[test]
fn error_tests() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let f = 2762159900.0f32;
let actual = unsafe { std::str::from_utf8_unchecked(f.to_lexical(&mut buffer)) };
let roundtrip = actual.parse::<f32>();
assert_eq!(Ok(f), roundtrip);
let f = 77371252000000000000000000.0f32;
let actual = unsafe { std::str::from_utf8_unchecked(f.to_lexical(&mut buffer)) };
let roundtrip = actual.parse::<f32>();
assert_eq!(Ok(f), roundtrip);
}
#[test]
fn fuzz_tests() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let f = 355259285044678240000000000000000000000000000000000000000000f64;
let actual = unsafe { std::str::from_utf8_unchecked(f.to_lexical(&mut buffer)) };
let roundtrip = actual.parse::<f64>();
assert_eq!(Ok(f), roundtrip);
}
#[test]
fn special_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let actual = unsafe { std::str::from_utf8_unchecked(f64::NAN.to_lexical(&mut buffer)) };
assert_eq!(actual, "NaN");
let actual = unsafe { std::str::from_utf8_unchecked(f64::INFINITY.to_lexical(&mut buffer)) };
assert_eq!(actual, "inf");
const OPTIONS: Options =
Options::builder().nan_string(Some(b"nan")).inf_string(Some(b"Infinity")).build_strict();
let bytes = f64::NAN.to_lexical_with_options::<{ STANDARD }>(&mut buffer, &OPTIONS);
let actual = unsafe { std::str::from_utf8_unchecked(bytes) };
assert_eq!(actual, "nan");
let bytes = f64::INFINITY.to_lexical_with_options::<{ STANDARD }>(&mut buffer, &OPTIONS);
let actual = unsafe { std::str::from_utf8_unchecked(bytes) };
assert_eq!(actual, "Infinity");
}
#[test]
#[should_panic]
fn invalid_nan_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
const OPTIONS: Options = Options::builder().nan_string(None).build_strict();
f64::NAN.to_lexical_with_options::<{ STANDARD }>(&mut buffer, &OPTIONS);
}
#[test]
#[should_panic]
fn invalid_inf_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
const OPTIONS: Options = Options::builder().inf_string(None).build_strict();
f64::INFINITY.to_lexical_with_options::<{ STANDARD }>(&mut buffer, &OPTIONS);
}
#[test]
#[cfg(feature = "power-of-two")]
fn hex_test() {
use core::num;
use lexical_util::format::NumberFormatBuilder;
const BASE16_2_10: u128 = NumberFormatBuilder::new()
.mantissa_radix(16)
.exponent_base(num::NonZeroU8::new(2))
.exponent_radix(num::NonZeroU8::new(10))
.build_strict();
const HEX_OPTIONS: Options = Options::builder().exponent(b'^').build_unchecked();
let mut buffer = [b'\x00'; BUFFER_SIZE];
let float = 12345.0f64;
let result = float.to_lexical_with_options::<BASE16_2_10>(&mut buffer, &HEX_OPTIONS);
assert_eq!(result, b"3.039^12");
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,665 @@
#![cfg(feature = "compact")]
use core::num;
use lexical_util::constants::BUFFER_SIZE;
use lexical_util::format::NumberFormatBuilder;
use lexical_write_float::float::{ExtendedFloat80, RawFloat};
use lexical_write_float::{compact, Options, RoundMode};
const DECIMAL: u128 = NumberFormatBuilder::decimal();
fn check_normalize(mant: u64, exp: i32, ymant: u64, yexp: i32) {
let mut x = ExtendedFloat80 {
mant,
exp,
};
if x.mant != 0 {
assert_eq!(x.mant & (1 << 63), 0);
compact::normalize(&mut x);
assert_eq!(x.mant & (1 << 63), 1 << 63);
}
assert_eq!(x, ExtendedFloat80 {
mant: ymant,
exp: yexp
});
}
#[test]
fn normalize_test() {
// f32 cases
check_normalize(0, 0, 0, 0);
check_normalize(1, -149, 9223372036854775808, -212);
check_normalize(71362, -149, 10043308644012916736, -196);
check_normalize(12379400, -90, 13611294244890214400, -130);
check_normalize(8388608, -23, 9223372036854775808, -63);
check_normalize(11368684, 43, 12500000250510966784, 3);
check_normalize(16777213, 104, 18446740775174668288, 64);
// Test a few cases from radix float writer errors.
check_normalize(5178144, -22, 11386859076597055488, -63);
// f64 cases
check_normalize(1, -1074, 9223372036854775808, -1137);
check_normalize(6448907850777164, -883, 13207363278391631872, -894);
check_normalize(7371020360979573, -551, 15095849699286165504, -562);
check_normalize(6427752177035961, -202, 13164036458569648128, -213);
check_normalize(4903985730770844, -185, 10043362776618688512, -196);
check_normalize(6646139978924579, -119, 13611294676837537792, -130);
check_normalize(4503599627370496, -52, 9223372036854775808, -63);
check_normalize(6103515625000000, 14, 12500000000000000000, 3);
check_normalize(8271806125530277, 80, 16940658945086007296, 69);
check_normalize(5503284107318959, 446, 11270725851789228032, 435);
check_normalize(6290184345309700, 778, 12882297539194265600, 767);
check_normalize(9007199254740991, 971, 18446744073709549568, 960);
// Check with errors from power-of-two.
check_normalize(72057594037927936, -1078, 9223372036854775808, -1085);
}
#[test]
fn normalized_boundaries_test() {
let fp = ExtendedFloat80 {
mant: 4503599627370496,
exp: -50,
};
let u = ExtendedFloat80 {
mant: 9223372036854775296,
exp: -61,
};
let l = ExtendedFloat80 {
mant: 9223372036854776832,
exp: -61,
};
let (upper, lower) = compact::normalized_boundaries::<f64>(&fp);
assert_eq!(upper, u);
assert_eq!(lower, l);
}
#[test]
fn from_f32_test() {
assert_eq!(compact::from_float(0.0f32), ExtendedFloat80 {
mant: 0,
exp: -149
});
assert_eq!(compact::from_float(-0.0f32), ExtendedFloat80 {
mant: 0,
exp: -149
});
assert_eq!(compact::from_float(1e-45f32), ExtendedFloat80 {
mant: 1,
exp: -149
});
assert_eq!(compact::from_float(1e-40f32), ExtendedFloat80 {
mant: 71362,
exp: -149
});
assert_eq!(compact::from_float(2e-40f32), ExtendedFloat80 {
mant: 142725,
exp: -149
});
assert_eq!(compact::from_float(1e-20f32), ExtendedFloat80 {
mant: 12379400,
exp: -90
});
assert_eq!(compact::from_float(2e-20f32), ExtendedFloat80 {
mant: 12379400,
exp: -89
});
assert_eq!(compact::from_float(1.0f32), ExtendedFloat80 {
mant: 8388608,
exp: -23
});
assert_eq!(compact::from_float(2.0f32), ExtendedFloat80 {
mant: 8388608,
exp: -22
});
assert_eq!(compact::from_float(1e20f32), ExtendedFloat80 {
mant: 11368684,
exp: 43
});
assert_eq!(compact::from_float(2e20f32), ExtendedFloat80 {
mant: 11368684,
exp: 44
});
assert_eq!(compact::from_float(3.402823e38f32), ExtendedFloat80 {
mant: 16777213,
exp: 104
});
}
#[test]
fn from_f64_test() {
assert_eq!(compact::from_float(0.0f64), ExtendedFloat80 {
mant: 0,
exp: -1074
});
assert_eq!(compact::from_float(-0.0f64), ExtendedFloat80 {
mant: 0,
exp: -1074
});
assert_eq!(compact::from_float(5e-324f64), ExtendedFloat80 {
mant: 1,
exp: -1074
});
assert_eq!(compact::from_float(1e-250f64), ExtendedFloat80 {
mant: 6448907850777164,
exp: -883
});
assert_eq!(compact::from_float(1e-150f64), ExtendedFloat80 {
mant: 7371020360979573,
exp: -551
});
assert_eq!(compact::from_float(1e-45f64), ExtendedFloat80 {
mant: 6427752177035961,
exp: -202
});
assert_eq!(compact::from_float(1e-40f64), ExtendedFloat80 {
mant: 4903985730770844,
exp: -185
});
assert_eq!(compact::from_float(2e-40f64), ExtendedFloat80 {
mant: 4903985730770844,
exp: -184
});
assert_eq!(compact::from_float(1e-20f64), ExtendedFloat80 {
mant: 6646139978924579,
exp: -119
});
assert_eq!(compact::from_float(2e-20f64), ExtendedFloat80 {
mant: 6646139978924579,
exp: -118
});
assert_eq!(compact::from_float(1.0f64), ExtendedFloat80 {
mant: 4503599627370496,
exp: -52
});
assert_eq!(compact::from_float(2.0f64), ExtendedFloat80 {
mant: 4503599627370496,
exp: -51
});
assert_eq!(compact::from_float(1e20f64), ExtendedFloat80 {
mant: 6103515625000000,
exp: 14
});
assert_eq!(compact::from_float(2e20f64), ExtendedFloat80 {
mant: 6103515625000000,
exp: 15
});
assert_eq!(compact::from_float(1e40f64), ExtendedFloat80 {
mant: 8271806125530277,
exp: 80
});
assert_eq!(compact::from_float(2e40f64), ExtendedFloat80 {
mant: 8271806125530277,
exp: 81
});
assert_eq!(compact::from_float(1e150f64), ExtendedFloat80 {
mant: 5503284107318959,
exp: 446
});
assert_eq!(compact::from_float(1e250f64), ExtendedFloat80 {
mant: 6290184345309700,
exp: 778
});
assert_eq!(compact::from_float(1.7976931348623157e308), ExtendedFloat80 {
mant: 9007199254740991,
exp: 971
});
}
fn check_mul(xmant: u64, xexp: i32, ymant: u64, yexp: i32, zmant: u64, zexp: i32) {
let x = ExtendedFloat80 {
mant: xmant,
exp: xexp,
};
let y = ExtendedFloat80 {
mant: ymant,
exp: yexp,
};
let z = ExtendedFloat80 {
mant: zmant,
exp: zexp,
};
let r = compact::mul(&x, &y);
assert_eq!(r, z);
}
#[test]
fn mul_test() {
// Normalized (64-bit mantissa)
check_mul(13164036458569648128, -213, 9223372036854775808, -62, 6582018229284824064, -211);
// Check both values need high bits set.
check_mul(1 << 32, -31, 1 << 32, -31, 1, 2);
check_mul(10 << 31, -31, 10 << 31, -31, 25, 2);
}
fn grisu<T: RawFloat>(f: T, expected: &str, k: i32) {
let mut buffer = [b'\x00'; 32];
let (count, real_k) = compact::grisu(f, &mut buffer);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
assert_eq!(k, real_k);
}
#[test]
fn grisu_test() {
// Useful test to ensure we don't have trailing zeros.
grisu(1.0f64, "1", 0);
grisu(0.1f64, "1", -1);
grisu(10.0f64, "1", 1);
grisu(100000000.0f64, "1", 8);
grisu(100001000.0f64, "100001", 3);
grisu(100111000.0f64, "100111", 3);
}
fn write_float<T: RawFloat, const FORMAT: u128>(f: T, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let count = compact::write_float::<_, FORMAT>(f, &mut buffer, options);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_test() {
const OPTS1: Options = Options::builder().build_strict();
write_float::<_, DECIMAL>(0.0f64, &OPTS1, "0.0");
write_float::<_, DECIMAL>(1.0f64, &OPTS1, "1.0");
write_float::<_, DECIMAL>(1.5f64, &OPTS1, "1.5");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &OPTS1, "1.2345678901234567");
write_float::<_, DECIMAL>(1.0e-17f64, &OPTS1, "1.0e-17");
write_float::<_, DECIMAL>(9.99999999999999e-16f64, &OPTS1, "9.99999999999999e-16");
write_float::<_, DECIMAL>(9.99999999999999e-15f64, &OPTS1, "9.99999999999999e-15");
write_float::<_, DECIMAL>(0.00999999999999999f64, &OPTS1, "0.00999999999999999");
write_float::<_, DECIMAL>(0.0999999999999999f64, &OPTS1, "0.0999999999999999");
write_float::<_, DECIMAL>(0.999999999999999f64, &OPTS1, "0.999999999999999");
write_float::<_, DECIMAL>(9.99999999999999f64, &OPTS1, "9.99999999999999");
write_float::<_, DECIMAL>(99.9999999999999f64, &OPTS1, "99.9999999999999");
write_float::<_, DECIMAL>(999.999999999999f64, &OPTS1, "999.999999999999");
write_float::<_, DECIMAL>(1000.0f64, &OPTS1, "1000.0");
write_float::<_, DECIMAL>(1.7976931348623157e308f64, &OPTS1, "1.7976931348623157e308");
write_float::<_, DECIMAL>(2.2250738585072014e-308f64, &OPTS1, "2.2250738585072014e-308");
const OPTS2: Options =
Options::builder().min_significant_digits(num::NonZeroUsize::new(50)).build_strict();
write_float::<_, DECIMAL>(
0.0f64,
&OPTS2,
"0.0000000000000000000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
1.0f64,
&OPTS2,
"1.0000000000000000000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
1.5f64,
&OPTS2,
"1.5000000000000000000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
1.2345678901234567890e0f64,
&OPTS2,
"1.2345678901234567000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
1.0e-17f64,
&OPTS2,
"1.0000000000000000000000000000000000000000000000000e-17",
);
write_float::<_, DECIMAL>(
9.99999999999999e-16f64,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000e-16",
);
write_float::<_, DECIMAL>(
9.99999999999999e-15f64,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000e-15",
);
write_float::<_, DECIMAL>(
0.00999999999999999f64,
&OPTS2,
"0.0099999999999999900000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
0.0999999999999999f64,
&OPTS2,
"0.099999999999999900000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
0.999999999999999f64,
&OPTS2,
"0.99999999999999900000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
9.99999999999999f64,
&OPTS2,
"9.9999999999999900000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
99.9999999999999f64,
&OPTS2,
"99.999999999999900000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
999.999999999999f64,
&OPTS2,
"999.99999999999900000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
1000.0f64,
&OPTS2,
"1000.0000000000000000000000000000000000000000000000",
);
write_float::<_, DECIMAL>(
1.7976931348623157e308f64,
&OPTS2,
"1.7976931348623157000000000000000000000000000000000e308",
);
write_float::<_, DECIMAL>(
2.2250738585072014e-308f64,
&OPTS2,
"2.2250738585072014000000000000000000000000000000000e-308",
);
const OPTS3: Options =
Options::builder().max_significant_digits(num::NonZeroUsize::new(5)).build_strict();
write_float::<_, DECIMAL>(0.0f64, &OPTS3, "0.0");
write_float::<_, DECIMAL>(1.0f64, &OPTS3, "1.0");
write_float::<_, DECIMAL>(1.5f64, &OPTS3, "1.5");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &OPTS3, "1.2346");
write_float::<_, DECIMAL>(1.0e-17f64, &OPTS3, "1.0e-17");
write_float::<_, DECIMAL>(9.99999999999999e-16f64, &OPTS3, "1.0e-15");
write_float::<_, DECIMAL>(9.99999999999999e-15f64, &OPTS3, "1.0e-14");
write_float::<_, DECIMAL>(0.00999999999999999f64, &OPTS3, "0.01");
write_float::<_, DECIMAL>(0.0999999999999999f64, &OPTS3, "0.1");
write_float::<_, DECIMAL>(0.999999999999999f64, &OPTS3, "1.0");
write_float::<_, DECIMAL>(9.99999999999999f64, &OPTS3, "10.0");
write_float::<_, DECIMAL>(99.9999999999999f64, &OPTS3, "100.0");
write_float::<_, DECIMAL>(999.999999999999f64, &OPTS3, "1000.0");
write_float::<_, DECIMAL>(1000.0f64, &OPTS3, "1000.0");
write_float::<_, DECIMAL>(1.7976931348623157e308f64, &OPTS3, "1.7977e308");
write_float::<_, DECIMAL>(2.2250738585072014e-308f64, &OPTS3, "2.2251e-308");
const OPTS4: Options = Options::builder().trim_floats(true).build_strict();
write_float::<_, DECIMAL>(0.0f64, &OPTS4, "0");
write_float::<_, DECIMAL>(1.0f64, &OPTS4, "1");
write_float::<_, DECIMAL>(1.5f64, &OPTS4, "1.5");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &OPTS4, "1.2345678901234567");
write_float::<_, DECIMAL>(1.0e-17f64, &OPTS4, "1e-17");
write_float::<_, DECIMAL>(9.99999999999999e-16f64, &OPTS4, "9.99999999999999e-16");
write_float::<_, DECIMAL>(9.99999999999999e-15f64, &OPTS4, "9.99999999999999e-15");
write_float::<_, DECIMAL>(0.00999999999999999f64, &OPTS4, "0.00999999999999999");
write_float::<_, DECIMAL>(0.0999999999999999f64, &OPTS4, "0.0999999999999999");
write_float::<_, DECIMAL>(0.999999999999999f64, &OPTS4, "0.999999999999999");
write_float::<_, DECIMAL>(9.99999999999999f64, &OPTS4, "9.99999999999999");
write_float::<_, DECIMAL>(99.9999999999999f64, &OPTS4, "99.9999999999999");
write_float::<_, DECIMAL>(999.999999999999f64, &OPTS4, "999.999999999999");
write_float::<_, DECIMAL>(1000.0f64, &OPTS4, "1000");
write_float::<_, DECIMAL>(1.7976931348623157e308f64, &OPTS4, "1.7976931348623157e308");
write_float::<_, DECIMAL>(2.2250738585072014e-308f64, &OPTS4, "2.2250738585072014e-308");
const OPTS5: Options = Options::builder()
.min_significant_digits(num::NonZeroUsize::new(50))
.trim_floats(true)
.build_strict();
write_float::<_, DECIMAL>(1.0e17f64, &OPTS5, "1e17");
write_float::<_, DECIMAL>(1.0e-17f64, &OPTS5, "1e-17");
write_float::<_, DECIMAL>(1000.0f64, &OPTS5, "1000");
write_float::<_, DECIMAL>(
9.99999999999999e16f64,
&OPTS5,
"9.9999999999999900000000000000000000000000000000000e16",
);
write_float::<_, DECIMAL>(
9.99999999999999e-16f64,
&OPTS5,
"9.9999999999999900000000000000000000000000000000000e-16",
);
const TRUNCATE: Options = Options::builder()
.max_significant_digits(num::NonZeroUsize::new(4))
.round_mode(RoundMode::Truncate)
.build_strict();
const ROUND: Options = Options::builder()
.max_significant_digits(num::NonZeroUsize::new(4))
.round_mode(RoundMode::Round)
.build_strict();
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &TRUNCATE, "1.234");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &ROUND, "1.235");
write_float::<_, DECIMAL>(1.2345678901234567890e1f64, &TRUNCATE, "12.34");
write_float::<_, DECIMAL>(1.2345678901234567890e1f64, &ROUND, "12.35");
write_float::<_, DECIMAL>(1.2345678901234567890e2f64, &TRUNCATE, "123.4");
write_float::<_, DECIMAL>(1.2345678901234567890e2f64, &ROUND, "123.5");
write_float::<_, DECIMAL>(1.2345678901234567890e3f64, &TRUNCATE, "1234.0");
write_float::<_, DECIMAL>(1.2345678901234567890e3f64, &ROUND, "1235.0");
// Check min and max digits
const OPTS6: Options = Options::builder()
.min_significant_digits(num::NonZeroUsize::new(3))
.max_significant_digits(num::NonZeroUsize::new(4))
.round_mode(RoundMode::Truncate)
.build_strict();
write_float::<_, DECIMAL>(0.0f64, &OPTS6, "0.00");
write_float::<_, DECIMAL>(1.5f64, &OPTS6, "1.50");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &OPTS6, "1.234");
}
// Test data for roundtrips.
const F32_DATA: [f32; 31] = [
0.,
0.1,
1.,
1.1,
12.,
12.1,
123.,
123.1,
1234.,
1234.1,
12345.,
12345.1,
123456.,
123456.1,
1234567.,
1234567.1,
12345678.,
12345678.1,
123456789.,
123456789.1,
123456789.12,
123456789.123,
123456789.1234,
123456789.12345,
1.2345678912345e8,
1.2345e+8,
1.2345e+11,
1.2345e+38,
1.2345e-8,
1.2345e-11,
1.2345e-38,
];
const F64_DATA: [f64; 33] = [
0.,
0.1,
1.,
1.1,
12.,
12.1,
123.,
123.1,
1234.,
1234.1,
12345.,
12345.1,
123456.,
123456.1,
1234567.,
1234567.1,
12345678.,
12345678.1,
123456789.,
123456789.1,
123456789.12,
123456789.123,
123456789.1234,
123456789.12345,
1.2345678912345e8,
1.2345e+8,
1.2345e+11,
1.2345e+38,
1.2345e+308,
1.2345e-8,
1.2345e-11,
1.2345e-38,
1.2345e-299,
];
#[test]
fn f32_test() {
const OPTIONS: Options = Options::builder().trim_floats(true).build_strict();
write_float::<_, DECIMAL>(0.0f32, &OPTIONS, "0");
write_float::<_, DECIMAL>(1.0f32, &OPTIONS, "1");
write_float::<_, DECIMAL>(10.0f32, &OPTIONS, "10");
write_float::<_, DECIMAL>(10.0f32, &OPTIONS, "10");
write_float::<_, DECIMAL>(1.2345678901234567890e0f32, &OPTIONS, "1.2345679");
write_float::<_, DECIMAL>(1.2345678901234567890e1f32, &OPTIONS, "12.345679");
write_float::<_, DECIMAL>(1.2345678901234567890e2f32, &OPTIONS, "123.45679");
write_float::<_, DECIMAL>(1.2345678901234567890e3f32, &OPTIONS, "1234.5679");
}
#[test]
fn f32_roundtrip_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
const OPTIONS: Options = Options::builder().build_strict();
for &float in F32_DATA.iter() {
let count = compact::write_float::<_, DECIMAL>(float, &mut buffer, &OPTIONS);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
let roundtrip = actual.parse::<f32>();
assert_eq!(roundtrip, Ok(float));
}
}
fn write_float_scientific(digits: &mut [u8], k: i32, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let ndigits = digits.len();
let count =
compact::write_float_scientific::<DECIMAL>(&mut buffer, digits, ndigits, k, &options);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
macro_rules! mut_b {
($x:literal) => {
&mut $x.to_vec()
};
}
#[test]
fn write_float_scientific_test() {
const OPTS1: Options = Options::new();
write_float_scientific(mut_b!(b"1"), 0, &OPTS1, "1.0e0");
write_float_scientific(mut_b!(b"999999999999999"), -1, &OPTS1, "9.99999999999999e-1");
write_float_scientific(mut_b!(b"999999999999999"), 0, &OPTS1, "9.99999999999999e0");
write_float_scientific(mut_b!(b"999999999999999"), -2, &OPTS1, "9.99999999999999e-2");
write_float_scientific(mut_b!(b"17976931348623157"), 308, &OPTS1, "1.7976931348623157e308");
write_float_scientific(mut_b!(b"22250738585072014"), -308, &OPTS1, "2.2250738585072014e-308");
const OPTS2: Options = Options::builder().trim_floats(true).build_strict();
write_float_scientific(mut_b!(b"1"), 0, &OPTS2, "1e0");
write_float_scientific(mut_b!(b"999999999999999"), -1, &OPTS2, "9.99999999999999e-1");
write_float_scientific(mut_b!(b"999999999999999"), 0, &OPTS2, "9.99999999999999e0");
write_float_scientific(mut_b!(b"999999999999999"), -2, &OPTS2, "9.99999999999999e-2");
write_float_scientific(mut_b!(b"17976931348623157"), 308, &OPTS2, "1.7976931348623157e308");
write_float_scientific(mut_b!(b"22250738585072014"), -308, &OPTS2, "2.2250738585072014e-308");
}
fn write_float_positive_exponent(digits: &mut [u8], k: i32, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; 512];
let ndigits = digits.len();
let count = compact::write_float_positive_exponent::<DECIMAL>(
&mut buffer,
digits,
ndigits,
k,
&options,
);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_positive_exponent_test() {
const OPTS1: Options = Options::new();
write_float_positive_exponent(&mut [b'1'], 0, &OPTS1, "1.0");
write_float_positive_exponent(mut_b!(b"999999999999999"), 0, &OPTS1, "9.99999999999999");
write_float_positive_exponent(mut_b!(b"999999999999999"), 1, &OPTS1, "99.9999999999999");
write_float_positive_exponent(mut_b!(b"999999999999999"), 2, &OPTS1, "999.999999999999");
write_float_positive_exponent(mut_b!(b"17976931348623157"), 308, &OPTS1, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0");
const OPTS2: Options = Options::builder().trim_floats(true).build_strict();
write_float_positive_exponent(&mut [b'1'], 0, &OPTS2, "1");
write_float_positive_exponent(mut_b!(b"999999999999999"), 0, &OPTS2, "9.99999999999999");
write_float_positive_exponent(mut_b!(b"999999999999999"), 1, &OPTS2, "99.9999999999999");
write_float_positive_exponent(mut_b!(b"999999999999999"), 2, &OPTS2, "999.999999999999");
write_float_positive_exponent(mut_b!(b"17976931348623157"), 308, &OPTS2, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
}
fn write_float_negative_exponent(digits: &mut [u8], k: i32, options: &Options, expected: &str) {
let mut buffer = [b'\x00'; 512];
let ndigits = digits.len();
let count = compact::write_float_negative_exponent::<DECIMAL>(
&mut buffer,
digits,
ndigits,
k,
&options,
);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_negative_exponent_test() {
const OPTS1: Options = Options::new();
write_float_negative_exponent(&mut [b'1'], -1, &OPTS1, "0.1");
write_float_negative_exponent(mut_b!(b"999999999999999"), -3, &OPTS1, "0.00999999999999999");
write_float_negative_exponent(mut_b!(b"999999999999999"), -2, &OPTS1, "0.0999999999999999");
write_float_negative_exponent(mut_b!(b"999999999999999"), -1, &OPTS1, "0.999999999999999");
write_float_negative_exponent(mut_b!(b"22250738585072014"), -308, &OPTS1, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014");
const OPTS2: Options = Options::builder().trim_floats(true).build_strict();
write_float_negative_exponent(&mut [b'1'], -1, &OPTS2, "0.1");
write_float_negative_exponent(mut_b!(b"999999999999999"), -3, &OPTS2, "0.00999999999999999");
write_float_negative_exponent(mut_b!(b"999999999999999"), -2, &OPTS2, "0.0999999999999999");
write_float_negative_exponent(mut_b!(b"999999999999999"), -1, &OPTS2, "0.999999999999999");
write_float_negative_exponent(mut_b!(b"22250738585072014"), -308, &OPTS2, "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014");
}
#[test]
fn f64_test() {
const OPTIONS: Options = Options::builder().trim_floats(true).build_strict();
write_float::<_, DECIMAL>(0.0f64, &OPTIONS, "0");
write_float::<_, DECIMAL>(1.0f64, &OPTIONS, "1");
write_float::<_, DECIMAL>(10.0f64, &OPTIONS, "10");
write_float::<_, DECIMAL>(10.0f64, &OPTIONS, "10");
write_float::<_, DECIMAL>(1.2345678901234567890e0f64, &OPTIONS, "1.2345678901234567");
write_float::<_, DECIMAL>(1.2345678901234567890e1f64, &OPTIONS, "12.345678901234567");
write_float::<_, DECIMAL>(1.2345678901234567890e2f64, &OPTIONS, "123.45678901234568");
write_float::<_, DECIMAL>(1.2345678901234567890e3f64, &OPTIONS, "1234.567890123457");
}
#[test]
fn f64_roundtrip_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
const OPTIONS: Options = Options::builder().build_strict();
for &float in F64_DATA.iter() {
let count = compact::write_float::<_, DECIMAL>(float, &mut buffer, &OPTIONS);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
let roundtrip = actual.parse::<f64>();
assert_eq!(roundtrip, Ok(float));
}
}
@@ -0,0 +1,412 @@
#![cfg(feature = "power-of-two")]
use core::num;
use lexical_util::constants::{FormattedSize, BUFFER_SIZE};
use lexical_util::format::NumberFormatBuilder;
use lexical_util::num::{Float, Integer};
use lexical_write_float::{binary, hex, Options};
use lexical_write_integer::write::WriteInteger;
const BASE4_2_10: u128 = NumberFormatBuilder::new()
.mantissa_radix(4)
.exponent_base(num::NonZeroU8::new(2))
.exponent_radix(num::NonZeroU8::new(10))
.build_strict();
const BASE8_2_10: u128 = NumberFormatBuilder::new()
.mantissa_radix(8)
.exponent_base(num::NonZeroU8::new(2))
.exponent_radix(num::NonZeroU8::new(10))
.build_strict();
const BASE16_2_10: u128 = NumberFormatBuilder::new()
.mantissa_radix(16)
.exponent_base(num::NonZeroU8::new(2))
.exponent_radix(num::NonZeroU8::new(10))
.build_strict();
const BASE32_2_10: u128 = NumberFormatBuilder::new()
.mantissa_radix(32)
.exponent_base(num::NonZeroU8::new(2))
.exponent_radix(num::NonZeroU8::new(10))
.build_strict();
const BASE16_4_10: u128 = NumberFormatBuilder::new()
.mantissa_radix(16)
.exponent_base(num::NonZeroU8::new(4))
.exponent_radix(num::NonZeroU8::new(10))
.build_strict();
const HEX_OPTIONS: Options = Options::builder().exponent(b'^').build_unchecked();
// NOTE: This doesn't handle float rounding or truncation.
// It assumes this has already been done.
fn write_float_scientific<T: Float, const FORMAT: u128>(f: T, options: &Options, expected: &str)
where
<T as Float>::Unsigned: WriteInteger + FormattedSize,
{
let mut buffer = [b'\x00'; BUFFER_SIZE];
let mantissa = f.mantissa();
let mantissa_bits = binary::significant_bits(mantissa) as i32;
let exp = f.exponent();
let mut sci_exp = exp + mantissa_bits - 1;
if mantissa == <T as Float>::Unsigned::ZERO {
sci_exp = 0;
}
let count =
hex::write_float_scientific::<_, FORMAT>(&mut buffer, mantissa, exp, sci_exp, options);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_scientific_test() {
// Positive exponent
// Check no formatting, base4/2.
const OPTS1: Options = Options::builder().build_strict();
write_float_scientific::<_, BASE4_2_10>(0.0f64, &OPTS1, "0.0e0");
write_float_scientific::<_, BASE4_2_10>(1.0f64, &OPTS1, "1.0e0");
write_float_scientific::<_, BASE4_2_10>(2.0f64, &OPTS1, "2.0e0");
write_float_scientific::<_, BASE4_2_10>(0.5f64, &OPTS1, "2.0e-2");
write_float_scientific::<_, BASE4_2_10>(
0.2345678901234567890e20f64,
&OPTS1,
"1.10112013100111033030021213e64",
);
write_float_scientific::<_, BASE4_2_10>(
0.1172839450617284e20f64,
&OPTS1,
"2.20230032200222132120103032e62",
);
write_float_scientific::<_, BASE4_2_10>(
0.0586419725308642e20f64,
&OPTS1,
"1.10112013100111033030021213e62",
);
write_float_scientific::<_, BASE4_2_10>(
0.0293209862654321e20f64,
&OPTS1,
"2.20230032200222132120103032e60",
);
write_float_scientific::<_, BASE4_2_10>(
0.01466049313271605e20f64,
&OPTS1,
"1.10112013100111033030021213e60",
);
write_float_scientific::<_, BASE4_2_10>(
0.2345678901234567890e-20f64,
&OPTS1,
"2.30103300013110301132322302e-70",
);
write_float_scientific::<_, BASE4_2_10>(
0.1172839450617284e-20f64,
&OPTS1,
"1.12021320003222120233131121e-70",
);
write_float_scientific::<_, BASE4_2_10>(
0.0586419725308642e-20f64,
&OPTS1,
"2.30103300013110301132322302e-72",
);
write_float_scientific::<_, BASE4_2_10>(
0.0293209862654321e-20f64,
&OPTS1,
"1.12021320003222120233131121e-72",
);
write_float_scientific::<_, BASE4_2_10>(
0.01466049313271605e-20f64,
&OPTS1,
"2.30103300013110301132322302e-74",
);
// Check no formatting, base8/2.
write_float_scientific::<_, BASE8_2_10>(0.0f64, &OPTS1, "0.0e0");
write_float_scientific::<_, BASE8_2_10>(1.0f64, &OPTS1, "1.0e0");
write_float_scientific::<_, BASE8_2_10>(2.0f64, &OPTS1, "2.0e0");
write_float_scientific::<_, BASE8_2_10>(0.5f64, &OPTS1, "4.0e-3");
write_float_scientific::<_, BASE8_2_10>(
0.2345678901234567890e20f64,
&OPTS1,
"2.42607202517141147e63",
);
write_float_scientific::<_, BASE8_2_10>(
0.1172839450617284e20f64,
&OPTS1,
"1.213035012474604634e63",
);
write_float_scientific::<_, BASE8_2_10>(
0.0586419725308642e20f64,
&OPTS1,
"5.05416405236302316e60",
);
write_float_scientific::<_, BASE8_2_10>(
0.0293209862654321e20f64,
&OPTS1,
"2.42607202517141147e60",
);
write_float_scientific::<_, BASE8_2_10>(
0.01466049313271605e20f64,
&OPTS1,
"1.213035012474604634e60",
);
write_float_scientific::<_, BASE8_2_10>(
0.2345678901234567890e-20f64,
&OPTS1,
"1.304740165142756544e-69",
);
write_float_scientific::<_, BASE8_2_10>(
0.1172839450617284e-20f64,
&OPTS1,
"5.42360072461367262e-72",
);
write_float_scientific::<_, BASE8_2_10>(
0.0586419725308642e-20f64,
&OPTS1,
"2.61170035230573531e-72",
);
write_float_scientific::<_, BASE8_2_10>(
0.0293209862654321e-20f64,
&OPTS1,
"1.304740165142756544e-72",
);
write_float_scientific::<_, BASE8_2_10>(
0.01466049313271605e-20f64,
&OPTS1,
"5.42360072461367262e-75",
);
// Check no formatting, base16/2.
write_float_scientific::<_, BASE16_2_10>(0.0f64, &HEX_OPTIONS, "0.0^0");
write_float_scientific::<_, BASE16_2_10>(1.0f64, &HEX_OPTIONS, "1.0^0");
write_float_scientific::<_, BASE16_2_10>(2.0f64, &HEX_OPTIONS, "2.0^0");
write_float_scientific::<_, BASE16_2_10>(0.5f64, &HEX_OPTIONS, "8.0^-4");
write_float_scientific::<_, BASE16_2_10>(
0.2345678901234567890e20f64,
&HEX_OPTIONS,
"1.45874153CC267^64",
);
write_float_scientific::<_, BASE16_2_10>(
0.1172839450617284e20f64,
&HEX_OPTIONS,
"A.2C3A0A9E61338^60",
);
write_float_scientific::<_, BASE16_2_10>(
0.0586419725308642e20f64,
&HEX_OPTIONS,
"5.161D054F3099C^60",
);
write_float_scientific::<_, BASE16_2_10>(
0.0293209862654321e20f64,
&HEX_OPTIONS,
"2.8B0E82A7984CE^60",
);
write_float_scientific::<_, BASE16_2_10>(
0.01466049313271605e20f64,
&HEX_OPTIONS,
"1.45874153CC267^60",
);
write_float_scientific::<_, BASE16_2_10>(
0.2345678901234567890e-20f64,
&HEX_OPTIONS,
"B.13C075317BAC8^-72",
);
write_float_scientific::<_, BASE16_2_10>(
0.1172839450617284e-20f64,
&HEX_OPTIONS,
"5.89E03A98BDD64^-72",
);
write_float_scientific::<_, BASE16_2_10>(
0.0586419725308642e-20f64,
&HEX_OPTIONS,
"2.C4F01D4C5EEB2^-72",
);
write_float_scientific::<_, BASE16_2_10>(
0.0293209862654321e-20f64,
&HEX_OPTIONS,
"1.62780EA62F759^-72",
);
write_float_scientific::<_, BASE16_2_10>(
0.01466049313271605e-20f64,
&HEX_OPTIONS,
"B.13C075317BAC8^-76",
);
// Check no formatting, base32/2.
write_float_scientific::<_, BASE32_2_10>(0.0f64, &HEX_OPTIONS, "0.0^0");
write_float_scientific::<_, BASE32_2_10>(1.0f64, &HEX_OPTIONS, "1.0^0");
write_float_scientific::<_, BASE32_2_10>(2.0f64, &HEX_OPTIONS, "2.0^0");
write_float_scientific::<_, BASE32_2_10>(0.5f64, &HEX_OPTIONS, "G.0^-5");
write_float_scientific::<_, BASE32_2_10>(
0.2345678901234567890e20f64,
&HEX_OPTIONS,
"K.B1Q1AF62CS^60",
);
write_float_scientific::<_, BASE32_2_10>(
0.1172839450617284e20f64,
&HEX_OPTIONS,
"A.5GT0L7J16E^60",
);
write_float_scientific::<_, BASE32_2_10>(
0.0586419725308642e20f64,
&HEX_OPTIONS,
"5.2OEGAJPGJ7^60",
);
write_float_scientific::<_, BASE32_2_10>(
0.0293209862654321e20f64,
&HEX_OPTIONS,
"2.HC7859SO9JG^60",
);
write_float_scientific::<_, BASE32_2_10>(
0.01466049313271605e20f64,
&HEX_OPTIONS,
"1.8M3K2KUC4PO^60",
);
write_float_scientific::<_, BASE32_2_10>(
0.2345678901234567890e-20f64,
&HEX_OPTIONS,
"2.OJO1QJ2UTCG^-70",
);
write_float_scientific::<_, BASE32_2_10>(
0.1172839450617284e-20f64,
&HEX_OPTIONS,
"1.C9S0T9HFEM8^-70",
);
write_float_scientific::<_, BASE32_2_10>(
0.0586419725308642e-20f64,
&HEX_OPTIONS,
"M.4U0EKONNB4^-75",
);
write_float_scientific::<_, BASE32_2_10>(
0.0293209862654321e-20f64,
&HEX_OPTIONS,
"B.2F07ACBRLI^-75",
);
write_float_scientific::<_, BASE32_2_10>(
0.01466049313271605e-20f64,
&HEX_OPTIONS,
"5.H7G3L65TQP^-75",
);
// Check no formatting, base16/4.
write_float_scientific::<_, BASE16_4_10>(0.0f64, &HEX_OPTIONS, "0.0^0");
write_float_scientific::<_, BASE16_4_10>(1.0f64, &HEX_OPTIONS, "1.0^0");
write_float_scientific::<_, BASE16_4_10>(2.0f64, &HEX_OPTIONS, "2.0^0");
write_float_scientific::<_, BASE16_4_10>(0.5f64, &HEX_OPTIONS, "8.0^-2");
write_float_scientific::<_, BASE16_4_10>(
0.2345678901234567890e20f64,
&HEX_OPTIONS,
"1.45874153CC267^32",
);
write_float_scientific::<_, BASE16_4_10>(
0.1172839450617284e20f64,
&HEX_OPTIONS,
"A.2C3A0A9E61338^30",
);
write_float_scientific::<_, BASE16_4_10>(
0.0586419725308642e20f64,
&HEX_OPTIONS,
"5.161D054F3099C^30",
);
write_float_scientific::<_, BASE16_4_10>(
0.0293209862654321e20f64,
&HEX_OPTIONS,
"2.8B0E82A7984CE^30",
);
write_float_scientific::<_, BASE16_4_10>(
0.01466049313271605e20f64,
&HEX_OPTIONS,
"1.45874153CC267^30",
);
write_float_scientific::<_, BASE16_4_10>(
0.2345678901234567890e-20f64,
&HEX_OPTIONS,
"B.13C075317BAC8^-36",
);
write_float_scientific::<_, BASE16_4_10>(
0.1172839450617284e-20f64,
&HEX_OPTIONS,
"5.89E03A98BDD64^-36",
);
write_float_scientific::<_, BASE16_4_10>(
0.0586419725308642e-20f64,
&HEX_OPTIONS,
"2.C4F01D4C5EEB2^-36",
);
write_float_scientific::<_, BASE16_4_10>(
0.0293209862654321e-20f64,
&HEX_OPTIONS,
"1.62780EA62F759^-36",
);
write_float_scientific::<_, BASE16_4_10>(
0.01466049313271605e-20f64,
&HEX_OPTIONS,
"B.13C075317BAC8^-38",
);
// Check with a minimum number of digits.
const OPTS2: Options =
Options::builder().min_significant_digits(num::NonZeroUsize::new(5)).build_strict();
write_float_scientific::<_, BASE16_4_10>(0.0f64, &OPTS2, "0.0000e0");
write_float_scientific::<_, BASE16_4_10>(1.0f64, &OPTS2, "1.0000e0");
write_float_scientific::<_, BASE16_4_10>(2.0f64, &OPTS2, "2.0000e0");
write_float_scientific::<_, BASE16_4_10>(0.5f64, &OPTS2, "8.0000e-2");
write_float_scientific::<_, BASE16_4_10>(
0.2345678901234567890e2f64,
&OPTS2,
"1.774F01FED3264e2",
);
const OPTS3: Options = Options::builder()
.min_significant_digits(num::NonZeroUsize::new(5))
.trim_floats(true)
.build_strict();
write_float_scientific::<_, BASE16_4_10>(0.0f64, &OPTS3, "0e0");
write_float_scientific::<_, BASE16_4_10>(1.0f64, &OPTS3, "1e0");
write_float_scientific::<_, BASE16_4_10>(2.0f64, &OPTS3, "2e0");
write_float_scientific::<_, BASE16_4_10>(0.5f64, &OPTS3, "8e-2");
write_float_scientific::<_, BASE16_4_10>(
0.2345678901234567890e2f64,
&OPTS3,
"1.774F01FED3264e2",
);
// Check trimming floats
const OPTS4: Options = Options::builder().trim_floats(true).build_strict();
write_float_scientific::<_, BASE16_4_10>(1f32, &OPTS4, "1e0");
write_float_scientific::<_, BASE16_4_10>(1.4e-45f32, &OPTS4, "8e-76");
write_float_scientific::<_, BASE16_4_10>(1.2345678901234567890f32, &OPTS4, "1.3C0CA4e0");
}
// NOTE: This doesn't handle float rounding or truncation.
// It assumes this has already been done.
fn write_float<T: Float, const FORMAT: u128>(f: T, options: &Options, expected: &str)
where
<T as Float>::Unsigned: WriteInteger + FormattedSize,
{
let mut buffer = [b'\x00'; BUFFER_SIZE];
let count = hex::write_float::<_, FORMAT>(f, &mut buffer, options);
let actual = unsafe { std::str::from_utf8_unchecked(&buffer[..count]) };
assert_eq!(actual, expected);
}
#[test]
fn write_float_test() {
const OPTIONS: Options = Options::builder().build_strict();
write_float::<_, BASE4_2_10>(
0.2345678901234567890f64,
&OPTIONS,
"0.033000302210022030112133232",
);
write_float::<_, BASE4_2_10>(0.1172839450617284f64, &OPTIONS, "0.013200121102011012023033313");
write_float::<_, BASE4_2_10>(0.0586419725308642f64, &OPTIONS, "0.0033000302210022030112133232");
write_float::<_, BASE4_2_10>(0.0293209862654321f64, &OPTIONS, "1.3200121102011012023033313e-6");
write_float::<_, BASE4_2_10>(
0.01466049313271605f64,
&OPTIONS,
"3.3000302210022030112133232e-8",
);
}
@@ -0,0 +1,12 @@
use core::str;
use lexical_util::constants::BUFFER_SIZE;
use lexical_write_float::ToLexical;
#[test]
fn issue_94_test() {
let mut buffer = [b'\x00'; BUFFER_SIZE];
let neg0: f64 = -0.0;
let result = neg0.to_lexical(&mut buffer);
assert_eq!(str::from_utf8(result), Ok("-0.0"));
}
@@ -0,0 +1,125 @@
use core::num;
use lexical_write_float::options::{self, Options, OptionsBuilder};
#[test]
fn invalid_exponent_test() {
let mut builder = OptionsBuilder::new();
builder = builder.exponent(b'\x00');
assert!(!builder.is_valid());
builder = builder.exponent(b'\x7f');
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.exponent(b'^');
assert!(builder.is_valid());
assert!(builder.build().is_ok());
}
#[test]
fn invalid_decimal_point_test() {
let mut builder = OptionsBuilder::new();
builder = builder.decimal_point(b'\x00');
assert!(!builder.is_valid());
builder = builder.decimal_point(b'\x7f');
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.decimal_point(b',');
assert!(builder.is_valid());
assert!(builder.build().is_ok());
}
#[test]
fn invalid_nan_test() {
let mut builder = OptionsBuilder::new();
builder = builder.nan_string(Some(b"naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaan"));
assert!(!builder.is_valid());
builder = builder.nan_string(Some(b"inf"));
assert!(!builder.is_valid());
builder = builder.nan_string(Some(b"na00n"));
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.nan_string(Some(b"nan"));
assert!(builder.is_valid());
assert!(builder.build().is_ok());
builder = builder.nan_string(None);
assert!(builder.is_valid());
}
#[test]
fn invalid_inf_test() {
let mut builder = OptionsBuilder::new();
builder = builder.inf_string(Some(b"innnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnf"));
assert!(!builder.is_valid());
builder = builder.inf_string(Some(b"nan"));
assert!(!builder.is_valid());
builder = builder.inf_string(Some(b"in00f"));
assert!(!builder.is_valid());
assert!(builder.build().is_err());
builder = builder.inf_string(Some(b"inf"));
assert!(builder.is_valid());
assert!(builder.build().is_ok());
builder = builder.inf_string(None);
assert!(builder.is_valid());
}
#[test]
fn builder_test() {
let mut builder = OptionsBuilder::new();
builder = builder.max_significant_digits(num::NonZeroUsize::new(10));
builder = builder.min_significant_digits(num::NonZeroUsize::new(5));
builder = builder.positive_exponent_break(num::NonZeroI32::new(9));
builder = builder.negative_exponent_break(num::NonZeroI32::new(-9));
builder = builder.round_mode(options::RoundMode::Truncate);
builder = builder.trim_floats(true);
builder = builder.exponent(b'^');
builder = builder.decimal_point(b',');
builder = builder.nan_string(Some(b"nan"));
builder = builder.inf_string(Some(b"Infinity"));
assert_eq!(builder.get_max_significant_digits().unwrap().get(), 10);
assert_eq!(builder.get_min_significant_digits().unwrap().get(), 5);
assert_eq!(builder.get_positive_exponent_break().unwrap().get(), 9);
assert_eq!(builder.get_negative_exponent_break().unwrap().get(), -9);
assert_eq!(builder.get_round_mode(), options::RoundMode::Truncate);
assert_eq!(builder.get_trim_floats(), true);
assert_eq!(builder.get_exponent(), b'^');
assert_eq!(builder.get_decimal_point(), b',');
assert_eq!(builder.get_nan_string(), Some("nan".as_bytes()));
assert_eq!(builder.get_inf_string(), Some("Infinity".as_bytes()));
assert!(builder.is_valid());
assert_eq!(builder.build(), Ok(builder.build_unchecked()));
}
#[test]
#[allow(deprecated)]
fn options_test() {
let mut opts = Options::new();
opts.set_max_significant_digits(num::NonZeroUsize::new(10));
opts.set_min_significant_digits(num::NonZeroUsize::new(5));
opts.set_positive_exponent_break(num::NonZeroI32::new(9));
opts.set_negative_exponent_break(num::NonZeroI32::new(-9));
opts.set_round_mode(options::RoundMode::Truncate);
opts.set_trim_floats(true);
opts.set_exponent(b'^');
opts.set_decimal_point(b',');
opts.set_nan_string(Some(b"nan"));
opts.set_inf_string(Some(b"Infinity"));
assert_eq!(opts.max_significant_digits().unwrap().get(), 10);
assert_eq!(opts.min_significant_digits().unwrap().get(), 5);
assert_eq!(opts.positive_exponent_break().unwrap().get(), 9);
assert_eq!(opts.negative_exponent_break().unwrap().get(), -9);
assert_eq!(opts.round_mode(), options::RoundMode::Truncate);
assert_eq!(opts.trim_floats(), true);
assert_eq!(opts.exponent(), b'^');
assert_eq!(opts.decimal_point(), b',');
assert_eq!(opts.nan_string(), Some("nan".as_bytes()));
assert_eq!(opts.inf_string(), Some("Infinity".as_bytes()));
assert!(opts.is_valid());
assert_eq!(Options::builder(), OptionsBuilder::new());
assert_eq!(opts.rebuild().build(), Ok(opts));
}