#![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",
);
}