mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-28 11:17:26 +03:00
float: Add tests for f16 conversions to and from decimal
Extend the existing tests for `f32` and `f64` with versions that include `f16`'s new printing and parsing implementations. Co-authored-by: Speedy_Lex <alex.ciocildau@gmail.com>
This commit is contained in:
@@ -7,6 +7,20 @@
|
||||
const FPATHS_F64: &[FPath<f64>] =
|
||||
&[((0, 0, false, false), Some(0.0)), ((0, 0, false, false), Some(0.0))];
|
||||
|
||||
// FIXME(f16_f128): enable on all targets once possible.
|
||||
#[test]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn check_fast_path_f16() {
|
||||
const FPATHS_F16: &[FPath<f16>] =
|
||||
&[((0, 0, false, false), Some(0.0)), ((0, 0, false, false), Some(0.0))];
|
||||
for ((exponent, mantissa, negative, many_digits), expected) in FPATHS_F16.iter().copied() {
|
||||
let dec = Decimal { exponent, mantissa, negative, many_digits };
|
||||
let actual = dec.try_fast_path::<f16>();
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_fast_path_f32() {
|
||||
for ((exponent, mantissa, negative, many_digits), expected) in FPATHS_F32.iter().copied() {
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
use core::num::dec2flt::float::RawFloat;
|
||||
|
||||
// FIXME(f16_f128): enable on all targets once possible.
|
||||
#[test]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn test_f16_integer_decode() {
|
||||
assert_eq!(3.14159265359f16.integer_decode(), (1608, -9, 1));
|
||||
assert_eq!((-8573.5918555f16).integer_decode(), (1072, 3, -1));
|
||||
#[cfg(not(miri))] // miri doesn't have powf16
|
||||
assert_eq!(2f16.powf(14.0).integer_decode(), (1 << 10, 4, 1));
|
||||
assert_eq!(0f16.integer_decode(), (0, -25, 1));
|
||||
assert_eq!((-0f16).integer_decode(), (0, -25, -1));
|
||||
assert_eq!(f16::INFINITY.integer_decode(), (1 << 10, 6, 1));
|
||||
assert_eq!(f16::NEG_INFINITY.integer_decode(), (1 << 10, 6, -1));
|
||||
|
||||
// Ignore the "sign" (quiet / signalling flag) of NAN.
|
||||
// It can vary between runtime operations and LLVM folding.
|
||||
let (nan_m, nan_p, _nan_s) = f16::NAN.integer_decode();
|
||||
assert_eq!((nan_m, nan_p), (1536, 6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_integer_decode() {
|
||||
assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
|
||||
@@ -34,6 +53,27 @@ fn test_f64_integer_decode() {
|
||||
|
||||
/* Sanity checks of computed magic numbers */
|
||||
|
||||
// FIXME(f16_f128): enable on all targets once possible.
|
||||
#[test]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn test_f16_consts() {
|
||||
assert_eq!(<f16 as RawFloat>::INFINITY, f16::INFINITY);
|
||||
assert_eq!(<f16 as RawFloat>::NEG_INFINITY, -f16::INFINITY);
|
||||
assert_eq!(<f16 as RawFloat>::NAN.to_bits(), f16::NAN.to_bits());
|
||||
assert_eq!(<f16 as RawFloat>::NEG_NAN.to_bits(), (-f16::NAN).to_bits());
|
||||
assert_eq!(<f16 as RawFloat>::SIG_BITS, 10);
|
||||
assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_ROUND_TO_EVEN, -22);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_ROUND_TO_EVEN, 5);
|
||||
assert_eq!(<f16 as RawFloat>::MIN_EXPONENT_FAST_PATH, -4);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_FAST_PATH, 4);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_EXPONENT_DISGUISED_FAST_PATH, 7);
|
||||
assert_eq!(<f16 as RawFloat>::EXP_MIN, -14);
|
||||
assert_eq!(<f16 as RawFloat>::EXP_SAT, 0x1f);
|
||||
assert_eq!(<f16 as RawFloat>::SMALLEST_POWER_OF_TEN, -27);
|
||||
assert_eq!(<f16 as RawFloat>::LARGEST_POWER_OF_TEN, 4);
|
||||
assert_eq!(<f16 as RawFloat>::MAX_MANTISSA_FAST_PATH, 2048);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f32_consts() {
|
||||
assert_eq!(<f32 as RawFloat>::INFINITY, f32::INFINITY);
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
use core::num::dec2flt::float::RawFloat;
|
||||
use core::num::dec2flt::lemire::compute_float;
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn compute_float16(q: i64, w: u64) -> (i32, u64) {
|
||||
let fp = compute_float::<f16>(q, w);
|
||||
(fp.p_biased, fp.m)
|
||||
}
|
||||
|
||||
fn compute_float32(q: i64, w: u64) -> (i32, u64) {
|
||||
let fp = compute_float::<f32>(q, w);
|
||||
(fp.p_biased, fp.m)
|
||||
@@ -11,23 +17,73 @@ fn compute_float64(q: i64, w: u64) -> (i32, u64) {
|
||||
(fp.p_biased, fp.m)
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): enable on all targets once possible.
|
||||
#[test]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn compute_float_f16_rounding() {
|
||||
// The maximum integer that cna be converted to a `f16` without lost precision.
|
||||
let val = 1 << 11;
|
||||
let scale = 10_u64.pow(10);
|
||||
|
||||
// These test near-halfway cases for half-precision floats.
|
||||
assert_eq!(compute_float16(0, val), (26, 0));
|
||||
assert_eq!(compute_float16(0, val + 1), (26, 0));
|
||||
assert_eq!(compute_float16(0, val + 2), (26, 1));
|
||||
assert_eq!(compute_float16(0, val + 3), (26, 2));
|
||||
assert_eq!(compute_float16(0, val + 4), (26, 2));
|
||||
|
||||
// For the next power up, the two nearest representable numbers are twice as far apart.
|
||||
let val2 = 1 << 12;
|
||||
assert_eq!(compute_float16(0, val2), (27, 0));
|
||||
assert_eq!(compute_float16(0, val2 + 2), (27, 0));
|
||||
assert_eq!(compute_float16(0, val2 + 4), (27, 1));
|
||||
assert_eq!(compute_float16(0, val2 + 6), (27, 2));
|
||||
assert_eq!(compute_float16(0, val2 + 8), (27, 2));
|
||||
|
||||
// These are examples of the above tests, with digits from the exponent shifted
|
||||
// to the mantissa.
|
||||
assert_eq!(compute_float16(-10, val * scale), (26, 0));
|
||||
assert_eq!(compute_float16(-10, (val + 1) * scale), (26, 0));
|
||||
assert_eq!(compute_float16(-10, (val + 2) * scale), (26, 1));
|
||||
// Let's check the lines to see if anything is different in table...
|
||||
assert_eq!(compute_float16(-10, (val + 3) * scale), (26, 2));
|
||||
assert_eq!(compute_float16(-10, (val + 4) * scale), (26, 2));
|
||||
|
||||
// Check the rounding point between infinity and the next representable number down
|
||||
assert_eq!(compute_float16(4, 6), (f16::INFINITE_POWER - 1, 851));
|
||||
assert_eq!(compute_float16(4, 7), (f16::INFINITE_POWER, 0)); // infinity
|
||||
assert_eq!(compute_float16(2, 655), (f16::INFINITE_POWER - 1, 1023));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compute_float_f32_rounding() {
|
||||
// These test near-halfway cases for single-precision floats.
|
||||
assert_eq!(compute_float32(0, 16777216), (151, 0));
|
||||
assert_eq!(compute_float32(0, 16777217), (151, 0));
|
||||
assert_eq!(compute_float32(0, 16777218), (151, 1));
|
||||
assert_eq!(compute_float32(0, 16777219), (151, 2));
|
||||
assert_eq!(compute_float32(0, 16777220), (151, 2));
|
||||
// the maximum integer that cna be converted to a `f32` without lost precision.
|
||||
let val = 1 << 24;
|
||||
let scale = 10_u64.pow(10);
|
||||
|
||||
// These are examples of the above tests, with
|
||||
// digits from the exponent shifted to the mantissa.
|
||||
assert_eq!(compute_float32(-10, 167772160000000000), (151, 0));
|
||||
assert_eq!(compute_float32(-10, 167772170000000000), (151, 0));
|
||||
assert_eq!(compute_float32(-10, 167772180000000000), (151, 1));
|
||||
// These test near-halfway cases for single-precision floats.
|
||||
assert_eq!(compute_float32(0, val), (151, 0));
|
||||
assert_eq!(compute_float32(0, val + 1), (151, 0));
|
||||
assert_eq!(compute_float32(0, val + 2), (151, 1));
|
||||
assert_eq!(compute_float32(0, val + 3), (151, 2));
|
||||
assert_eq!(compute_float32(0, val + 4), (151, 2));
|
||||
|
||||
// For the next power up, the two nearest representable numbers are twice as far apart.
|
||||
let val2 = 1 << 25;
|
||||
assert_eq!(compute_float32(0, val2), (152, 0));
|
||||
assert_eq!(compute_float32(0, val2 + 2), (152, 0));
|
||||
assert_eq!(compute_float32(0, val2 + 4), (152, 1));
|
||||
assert_eq!(compute_float32(0, val2 + 6), (152, 2));
|
||||
assert_eq!(compute_float32(0, val2 + 8), (152, 2));
|
||||
|
||||
// These are examples of the above tests, with digits from the exponent shifted
|
||||
// to the mantissa.
|
||||
assert_eq!(compute_float32(-10, val * scale), (151, 0));
|
||||
assert_eq!(compute_float32(-10, (val + 1) * scale), (151, 0));
|
||||
assert_eq!(compute_float32(-10, (val + 2) * scale), (151, 1));
|
||||
// Let's check the lines to see if anything is different in table...
|
||||
assert_eq!(compute_float32(-10, 167772190000000000), (151, 2));
|
||||
assert_eq!(compute_float32(-10, 167772200000000000), (151, 2));
|
||||
assert_eq!(compute_float32(-10, (val + 3) * scale), (151, 2));
|
||||
assert_eq!(compute_float32(-10, (val + 4) * scale), (151, 2));
|
||||
|
||||
// Check the rounding point between infinity and the next representable number down
|
||||
assert_eq!(compute_float32(38, 3), (f32::INFINITE_POWER - 1, 6402534));
|
||||
@@ -37,23 +93,38 @@ fn compute_float_f32_rounding() {
|
||||
|
||||
#[test]
|
||||
fn compute_float_f64_rounding() {
|
||||
// These test near-halfway cases for double-precision floats.
|
||||
assert_eq!(compute_float64(0, 9007199254740992), (1076, 0));
|
||||
assert_eq!(compute_float64(0, 9007199254740993), (1076, 0));
|
||||
assert_eq!(compute_float64(0, 9007199254740994), (1076, 1));
|
||||
assert_eq!(compute_float64(0, 9007199254740995), (1076, 2));
|
||||
assert_eq!(compute_float64(0, 9007199254740996), (1076, 2));
|
||||
assert_eq!(compute_float64(0, 18014398509481984), (1077, 0));
|
||||
assert_eq!(compute_float64(0, 18014398509481986), (1077, 0));
|
||||
assert_eq!(compute_float64(0, 18014398509481988), (1077, 1));
|
||||
assert_eq!(compute_float64(0, 18014398509481990), (1077, 2));
|
||||
assert_eq!(compute_float64(0, 18014398509481992), (1077, 2));
|
||||
// The maximum integer that cna be converted to a `f64` without lost precision.
|
||||
let val = 1 << 53;
|
||||
let scale = 1000;
|
||||
|
||||
// These are examples of the above tests, with
|
||||
// digits from the exponent shifted to the mantissa.
|
||||
assert_eq!(compute_float64(-3, 9007199254740992000), (1076, 0));
|
||||
assert_eq!(compute_float64(-3, 9007199254740993000), (1076, 0));
|
||||
assert_eq!(compute_float64(-3, 9007199254740994000), (1076, 1));
|
||||
assert_eq!(compute_float64(-3, 9007199254740995000), (1076, 2));
|
||||
assert_eq!(compute_float64(-3, 9007199254740996000), (1076, 2));
|
||||
// These test near-halfway cases for double-precision floats.
|
||||
assert_eq!(compute_float64(0, val), (1076, 0));
|
||||
assert_eq!(compute_float64(0, val + 1), (1076, 0));
|
||||
assert_eq!(compute_float64(0, val + 2), (1076, 1));
|
||||
assert_eq!(compute_float64(0, val + 3), (1076, 2));
|
||||
assert_eq!(compute_float64(0, val + 4), (1076, 2));
|
||||
|
||||
// For the next power up, the two nearest representable numbers are twice as far apart.
|
||||
let val2 = 1 << 54;
|
||||
assert_eq!(compute_float64(0, val2), (1077, 0));
|
||||
assert_eq!(compute_float64(0, val2 + 2), (1077, 0));
|
||||
assert_eq!(compute_float64(0, val2 + 4), (1077, 1));
|
||||
assert_eq!(compute_float64(0, val2 + 6), (1077, 2));
|
||||
assert_eq!(compute_float64(0, val2 + 8), (1077, 2));
|
||||
|
||||
// These are examples of the above tests, with digits from the exponent shifted
|
||||
// to the mantissa.
|
||||
assert_eq!(compute_float64(-3, val * scale), (1076, 0));
|
||||
assert_eq!(compute_float64(-3, (val + 1) * scale), (1076, 0));
|
||||
assert_eq!(compute_float64(-3, (val + 2) * scale), (1076, 1));
|
||||
assert_eq!(compute_float64(-3, (val + 3) * scale), (1076, 2));
|
||||
assert_eq!(compute_float64(-3, (val + 4) * scale), (1076, 2));
|
||||
|
||||
// Check the rounding point between infinity and the next representable number down
|
||||
assert_eq!(compute_float64(308, 1), (f64::INFINITE_POWER - 1, 506821272651936));
|
||||
assert_eq!(compute_float64(308, 2), (f64::INFINITE_POWER, 0)); // infinity
|
||||
assert_eq!(
|
||||
compute_float64(292, 17976931348623157),
|
||||
(f64::INFINITE_POWER - 1, 4503599627370495)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,15 +11,23 @@
|
||||
// Requires a *polymorphic literal*, i.e., one that can serve as f64 as well as f32.
|
||||
macro_rules! test_literal {
|
||||
($x: expr) => {{
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
let x16: f16 = $x;
|
||||
let x32: f32 = $x;
|
||||
let x64: f64 = $x;
|
||||
let inputs = &[stringify!($x).into(), format!("{:?}", x64), format!("{:e}", x64)];
|
||||
|
||||
for input in inputs {
|
||||
assert_eq!(input.parse(), Ok(x64));
|
||||
assert_eq!(input.parse(), Ok(x32));
|
||||
assert_eq!(input.parse(), Ok(x64), "failed f64 {input}");
|
||||
assert_eq!(input.parse(), Ok(x32), "failed f32 {input}");
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert_eq!(input.parse(), Ok(x16), "failed f16 {input}");
|
||||
|
||||
let neg_input = format!("-{input}");
|
||||
assert_eq!(neg_input.parse(), Ok(-x64));
|
||||
assert_eq!(neg_input.parse(), Ok(-x32));
|
||||
assert_eq!(neg_input.parse(), Ok(-x64), "failed f64 {neg_input}");
|
||||
assert_eq!(neg_input.parse(), Ok(-x32), "failed f32 {neg_input}");
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert_eq!(neg_input.parse(), Ok(-x16), "failed f16 {neg_input}");
|
||||
}
|
||||
}};
|
||||
}
|
||||
@@ -84,48 +92,87 @@ fn fast_path_correct() {
|
||||
test_literal!(1.448997445238699);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): remove gates once tests work on all targets
|
||||
|
||||
#[test]
|
||||
fn lonely_dot() {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert!(".".parse::<f16>().is_err());
|
||||
assert!(".".parse::<f32>().is_err());
|
||||
assert!(".".parse::<f64>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exponentiated_dot() {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert!(".e0".parse::<f16>().is_err());
|
||||
assert!(".e0".parse::<f32>().is_err());
|
||||
assert!(".e0".parse::<f64>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lonely_sign() {
|
||||
assert!("+".parse::<f32>().is_err());
|
||||
assert!("-".parse::<f64>().is_err());
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert!("+".parse::<f16>().is_err());
|
||||
assert!("-".parse::<f32>().is_err());
|
||||
assert!("+".parse::<f64>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn whitespace() {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert!("1.0 ".parse::<f16>().is_err());
|
||||
assert!(" 1.0".parse::<f32>().is_err());
|
||||
assert!("1.0 ".parse::<f64>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nan() {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
assert!("NaN".parse::<f16>().unwrap().is_nan());
|
||||
assert!("-NaN".parse::<f16>().unwrap().is_nan());
|
||||
}
|
||||
|
||||
assert!("NaN".parse::<f32>().unwrap().is_nan());
|
||||
assert!("-NaN".parse::<f32>().unwrap().is_nan());
|
||||
|
||||
assert!("NaN".parse::<f64>().unwrap().is_nan());
|
||||
assert!("-NaN".parse::<f64>().unwrap().is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inf() {
|
||||
assert_eq!("inf".parse(), Ok(f64::INFINITY));
|
||||
assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY));
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
assert_eq!("inf".parse(), Ok(f16::INFINITY));
|
||||
assert_eq!("-inf".parse(), Ok(f16::NEG_INFINITY));
|
||||
}
|
||||
|
||||
assert_eq!("inf".parse(), Ok(f32::INFINITY));
|
||||
assert_eq!("-inf".parse(), Ok(f32::NEG_INFINITY));
|
||||
|
||||
assert_eq!("inf".parse(), Ok(f64::INFINITY));
|
||||
assert_eq!("-inf".parse(), Ok(f64::NEG_INFINITY));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn massive_exponent() {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
let max = i16::MAX;
|
||||
assert_eq!(format!("1e{max}000").parse(), Ok(f16::INFINITY));
|
||||
assert_eq!(format!("1e-{max}000").parse(), Ok(0.0f16));
|
||||
assert_eq!(format!("1e{max}000").parse(), Ok(f16::INFINITY));
|
||||
}
|
||||
|
||||
let max = i32::MAX;
|
||||
assert_eq!(format!("1e{max}000").parse(), Ok(f32::INFINITY));
|
||||
assert_eq!(format!("1e-{max}000").parse(), Ok(0.0f32));
|
||||
assert_eq!(format!("1e{max}000").parse(), Ok(f32::INFINITY));
|
||||
|
||||
let max = i64::MAX;
|
||||
assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
|
||||
assert_eq!(format!("1e-{max}000").parse(), Ok(0.0));
|
||||
assert_eq!(format!("1e-{max}000").parse(), Ok(0.0f64));
|
||||
assert_eq!(format!("1e{max}000").parse(), Ok(f64::INFINITY));
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ fn new_dec(e: i64, m: u64) -> Decimal {
|
||||
fn missing_pieces() {
|
||||
let permutations = &[".e", "1e", "e4", "e", ".12e", "321.e", "32.12e+", "12.32e-"];
|
||||
for &s in permutations {
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert_eq!(dec2flt::<f16>(s), Err(pfe_invalid()));
|
||||
assert_eq!(dec2flt::<f32>(s), Err(pfe_invalid()));
|
||||
assert_eq!(dec2flt::<f64>(s), Err(pfe_invalid()));
|
||||
}
|
||||
}
|
||||
@@ -17,15 +20,31 @@ fn missing_pieces() {
|
||||
#[test]
|
||||
fn invalid_chars() {
|
||||
let invalid = "r,?<j";
|
||||
let error = Err(pfe_invalid());
|
||||
let valid_strings = &["123", "666.", ".1", "5e1", "7e-3", "0.0e+1"];
|
||||
|
||||
for c in invalid.chars() {
|
||||
for s in valid_strings {
|
||||
for i in 0..s.len() {
|
||||
let mut input = String::new();
|
||||
input.push_str(s);
|
||||
input.insert(i, c);
|
||||
assert!(dec2flt::<f64>(&input) == error, "did not reject invalid {:?}", input);
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
assert_eq!(
|
||||
dec2flt::<f16>(&input),
|
||||
Err(pfe_invalid()),
|
||||
"f16 did not reject invalid {input:?}",
|
||||
);
|
||||
assert_eq!(
|
||||
dec2flt::<f32>(&input),
|
||||
Err(pfe_invalid()),
|
||||
"f32 did not reject invalid {input:?}",
|
||||
);
|
||||
assert_eq!(
|
||||
dec2flt::<f64>(&input),
|
||||
Err(pfe_invalid()),
|
||||
"f64 did not reject invalid {input:?}",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ mod strategy {
|
||||
pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
|
||||
match decode(v).1 {
|
||||
FullDecoded::Finite(decoded) => decoded,
|
||||
full_decoded => panic!("expected finite, got {full_decoded:?} instead"),
|
||||
full_decoded => panic!("expected finite, got {full_decoded:?} instead for {v:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,11 @@ macro_rules! try_fixed {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn ldexp_f16(a: f16, b: i32) -> f16 {
|
||||
ldexp_f64(a as f64, b) as f16
|
||||
}
|
||||
|
||||
fn ldexp_f32(a: f32, b: i32) -> f32 {
|
||||
ldexp_f64(a as f64, b) as f32
|
||||
}
|
||||
@@ -176,6 +181,13 @@ trait TestableFloat: DecodableFloat + fmt::Display {
|
||||
fn ldexpi(f: i64, exp: isize) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
impl TestableFloat for f16 {
|
||||
fn ldexpi(f: i64, exp: isize) -> Self {
|
||||
f as Self * (exp as Self).exp2()
|
||||
}
|
||||
}
|
||||
|
||||
impl TestableFloat for f32 {
|
||||
fn ldexpi(f: i64, exp: isize) -> Self {
|
||||
f as Self * (exp as Self).exp2()
|
||||
@@ -225,6 +237,76 @@ macro_rules! check_exact_one {
|
||||
//
|
||||
// [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion
|
||||
// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z
|
||||
// or https://www.icir.org/vern/papers/testbase-report.pdf
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
pub fn f16_shortest_sanity_test<F>(mut f: F)
|
||||
where
|
||||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
|
||||
{
|
||||
// 0.0999145507813
|
||||
// 0.0999755859375
|
||||
// 0.100036621094
|
||||
check_shortest!(f(0.1f16) => b"1", 0);
|
||||
|
||||
// 0.3330078125
|
||||
// 0.333251953125 (1/3 in the default rounding)
|
||||
// 0.33349609375
|
||||
check_shortest!(f(1.0f16/3.0) => b"3333", 0);
|
||||
|
||||
// 10^1 * 0.3138671875
|
||||
// 10^1 * 0.3140625
|
||||
// 10^1 * 0.3142578125
|
||||
check_shortest!(f(3.14f16) => b"314", 1);
|
||||
|
||||
// 10^18 * 0.31415916243714048
|
||||
// 10^18 * 0.314159196796878848
|
||||
// 10^18 * 0.314159231156617216
|
||||
check_shortest!(f(3.1415e4f16) => b"3141", 5);
|
||||
|
||||
// regression test for decoders
|
||||
// 10^2 * 0.31984375
|
||||
// 10^2 * 0.32
|
||||
// 10^2 * 0.3203125
|
||||
check_shortest!(f(ldexp_f16(1.0, 5)) => b"32", 2);
|
||||
|
||||
// 10^5 * 0.65472
|
||||
// 10^5 * 0.65504
|
||||
// 10^5 * 0.65536
|
||||
check_shortest!(f(f16::MAX) => b"655", 5);
|
||||
|
||||
// 10^-4 * 0.60975551605224609375
|
||||
// 10^-4 * 0.6103515625
|
||||
// 10^-4 * 0.61094760894775390625
|
||||
check_shortest!(f(f16::MIN_POSITIVE) => b"6104", -4);
|
||||
|
||||
// 10^-9 * 0
|
||||
// 10^-9 * 0.59604644775390625
|
||||
// 10^-8 * 0.11920928955078125
|
||||
let minf16 = ldexp_f16(1.0, -24);
|
||||
check_shortest!(f(minf16) => b"6", -7);
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
pub fn f16_exact_sanity_test<F>(mut f: F)
|
||||
where
|
||||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>], i16) -> (&'a [u8], i16),
|
||||
{
|
||||
let minf16 = ldexp_f16(1.0, -24);
|
||||
|
||||
check_exact!(f(0.1f16) => b"999755859375 ", -1);
|
||||
check_exact!(f(0.5f16) => b"5 ", 0);
|
||||
check_exact!(f(1.0f16/3.0) => b"333251953125 ", 0);
|
||||
check_exact!(f(3.141f16) => b"3140625 ", 1);
|
||||
check_exact!(f(3.141e4f16) => b"31408 ", 5);
|
||||
check_exact!(f(f16::MAX) => b"65504 ", 5);
|
||||
check_exact!(f(f16::MIN_POSITIVE) => b"6103515625 ", -4);
|
||||
check_exact!(f(minf16) => b"59604644775390625", -7);
|
||||
|
||||
// FIXME(f16_f128): these should gain the check_exact_one tests like `f32` and `f64` have,
|
||||
// but these values are not easy to generate. The algorithm from the Paxon paper [1] needs
|
||||
// to be adapted to binary16.
|
||||
}
|
||||
|
||||
pub fn f32_shortest_sanity_test<F>(mut f: F)
|
||||
where
|
||||
@@ -553,23 +635,45 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
|
||||
assert_eq!(to_string(f, 1.9971e20, Minus, 1), "199710000000000000000.0");
|
||||
assert_eq!(to_string(f, 1.9971e20, Minus, 8), "199710000000000000000.00000000");
|
||||
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", ""));
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", ""));
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", ""));
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
// f16
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 0), "65500");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 1), "65500.0");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 8), "65500.00000000");
|
||||
|
||||
let minf32 = ldexp_f32(1.0, -149);
|
||||
assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", ""));
|
||||
assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", ""));
|
||||
assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", ""));
|
||||
let minf16 = ldexp_f16(1.0, -24);
|
||||
assert_eq!(to_string(f, minf16, Minus, 0), "0.00000006");
|
||||
assert_eq!(to_string(f, minf16, Minus, 8), "0.00000006");
|
||||
assert_eq!(to_string(f, minf16, Minus, 9), "0.000000060");
|
||||
}
|
||||
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", ""));
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", ""));
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, 8), format!("17976931348623157{:0>292}.00000000", ""));
|
||||
{
|
||||
// f32
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 0), format!("34028235{:0>31}", ""));
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 1), format!("34028235{:0>31}.0", ""));
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 8), format!("34028235{:0>31}.00000000", ""));
|
||||
|
||||
let minf64 = ldexp_f64(1.0, -1074);
|
||||
assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", ""));
|
||||
assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", ""));
|
||||
assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", ""));
|
||||
let minf32 = ldexp_f32(1.0, -149);
|
||||
assert_eq!(to_string(f, minf32, Minus, 0), format!("0.{:0>44}1", ""));
|
||||
assert_eq!(to_string(f, minf32, Minus, 45), format!("0.{:0>44}1", ""));
|
||||
assert_eq!(to_string(f, minf32, Minus, 46), format!("0.{:0>44}10", ""));
|
||||
}
|
||||
|
||||
{
|
||||
// f64
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, 0), format!("17976931348623157{:0>292}", ""));
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, 1), format!("17976931348623157{:0>292}.0", ""));
|
||||
assert_eq!(
|
||||
to_string(f, f64::MAX, Minus, 8),
|
||||
format!("17976931348623157{:0>292}.00000000", "")
|
||||
);
|
||||
|
||||
let minf64 = ldexp_f64(1.0, -1074);
|
||||
assert_eq!(to_string(f, minf64, Minus, 0), format!("0.{:0>323}5", ""));
|
||||
assert_eq!(to_string(f, minf64, Minus, 324), format!("0.{:0>323}5", ""));
|
||||
assert_eq!(to_string(f, minf64, Minus, 325), format!("0.{:0>323}50", ""));
|
||||
}
|
||||
|
||||
if cfg!(miri) {
|
||||
// Miri is too slow
|
||||
@@ -655,27 +759,45 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: b
|
||||
assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000");
|
||||
assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23");
|
||||
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", ""));
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
// f16
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, (-2, 2), false), "6.55e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, (-4, 4), false), "6.55e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, (-5, 5), false), "65500");
|
||||
|
||||
let minf32 = ldexp_f32(1.0, -149);
|
||||
assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45");
|
||||
assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45");
|
||||
assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", ""));
|
||||
let minf16 = ldexp_f16(1.0, -24);
|
||||
assert_eq!(to_string(f, minf16, Minus, (-2, 2), false), "6e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, (-7, 7), false), "6e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, (-8, 8), false), "0.00000006");
|
||||
}
|
||||
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308");
|
||||
assert_eq!(
|
||||
to_string(f, f64::MAX, Minus, (-308, 309), false),
|
||||
format!("17976931348623157{:0>292}", "")
|
||||
);
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308");
|
||||
{
|
||||
// f32
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, (-4, 16), false), "3.4028235e38");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", ""));
|
||||
|
||||
let minf64 = ldexp_f64(1.0, -1074);
|
||||
assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324");
|
||||
assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", ""));
|
||||
assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324");
|
||||
let minf32 = ldexp_f32(1.0, -149);
|
||||
assert_eq!(to_string(f, minf32, Minus, (-4, 16), false), "1e-45");
|
||||
assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45");
|
||||
assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", ""));
|
||||
}
|
||||
|
||||
{
|
||||
// f64
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, (-4, 16), false), "1.7976931348623157e308");
|
||||
assert_eq!(
|
||||
to_string(f, f64::MAX, Minus, (-308, 309), false),
|
||||
format!("17976931348623157{:0>292}", "")
|
||||
);
|
||||
assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), "1.7976931348623157e308");
|
||||
|
||||
let minf64 = ldexp_f64(1.0, -1074);
|
||||
assert_eq!(to_string(f, minf64, Minus, (-4, 16), false), "5e-324");
|
||||
assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", ""));
|
||||
assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324");
|
||||
}
|
||||
assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1");
|
||||
}
|
||||
|
||||
@@ -791,6 +913,26 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) ->
|
||||
"9.999999999999999547481118258862586856139387236908078193664550781250000e-7"
|
||||
);
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 1, false), "7e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 2, false), "6.6e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 4, false), "6.550e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 5, false), "6.5504e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 6, false), "6.55040e4");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 16, false), "6.550400000000000e4");
|
||||
|
||||
let minf16 = ldexp_f16(1.0, -24);
|
||||
assert_eq!(to_string(f, minf16, Minus, 1, false), "6e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 2, false), "6.0e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 4, false), "5.960e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 8, false), "5.9604645e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 16, false), "5.960464477539062e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 17, false), "5.9604644775390625e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 18, false), "5.96046447753906250e-8");
|
||||
assert_eq!(to_string(f, minf16, Minus, 24, false), "5.96046447753906250000000e-8");
|
||||
}
|
||||
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38");
|
||||
@@ -1069,6 +1211,13 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
|
||||
"0.000000999999999999999954748111825886258685613938723690807819366455078125000"
|
||||
);
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 0), "65504");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 1), "65504.0");
|
||||
assert_eq!(to_string(f, f16::MAX, Minus, 2), "65504.00");
|
||||
}
|
||||
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 0), "340282346638528859811704183484516925440");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 1), "340282346638528859811704183484516925440.0");
|
||||
assert_eq!(to_string(f, f32::MAX, Minus, 2), "340282346638528859811704183484516925440.00");
|
||||
@@ -1078,6 +1227,21 @@ fn to_string<T, F>(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
{
|
||||
let minf16 = ldexp_f16(1.0, -24);
|
||||
assert_eq!(to_string(f, minf16, Minus, 0), "0");
|
||||
assert_eq!(to_string(f, minf16, Minus, 1), "0.0");
|
||||
assert_eq!(to_string(f, minf16, Minus, 2), "0.00");
|
||||
assert_eq!(to_string(f, minf16, Minus, 4), "0.0000");
|
||||
assert_eq!(to_string(f, minf16, Minus, 8), "0.00000006");
|
||||
assert_eq!(to_string(f, minf16, Minus, 10), "0.0000000596");
|
||||
assert_eq!(to_string(f, minf16, Minus, 15), "0.000000059604645");
|
||||
assert_eq!(to_string(f, minf16, Minus, 20), "0.00000005960464477539");
|
||||
assert_eq!(to_string(f, minf16, Minus, 24), "0.000000059604644775390625");
|
||||
assert_eq!(to_string(f, minf16, Minus, 32), "0.00000005960464477539062500000000");
|
||||
}
|
||||
|
||||
let minf32 = ldexp_f32(1.0, -149);
|
||||
assert_eq!(to_string(f, minf32, Minus, 0), "0");
|
||||
assert_eq!(to_string(f, minf32, Minus, 1), "0.0");
|
||||
|
||||
@@ -79,6 +79,20 @@ fn iterate<F, G, V>(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V
|
||||
(npassed, nignored)
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
pub fn f16_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
|
||||
where
|
||||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
|
||||
G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
|
||||
{
|
||||
let mut rng = crate::test_rng();
|
||||
let f16_range = Uniform::new(0x0001u16, 0x7c00).unwrap();
|
||||
iterate("f16_random_equivalence_test", k, n, f, g, |_| {
|
||||
let x = f16::from_bits(f16_range.sample(&mut rng));
|
||||
decode_finite(x)
|
||||
});
|
||||
}
|
||||
|
||||
pub fn f32_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
|
||||
where
|
||||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
|
||||
@@ -105,6 +119,24 @@ pub fn f64_random_equivalence_test<F, G>(f: F, g: G, k: usize, n: usize)
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
pub fn f16_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
|
||||
where
|
||||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
|
||||
G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> (&'a [u8], i16),
|
||||
{
|
||||
// Unlike the other float types, `f16` is small enough that these exhaustive tests
|
||||
// can run in less than a second so we don't need to ignore it.
|
||||
|
||||
// iterate from 0x0001 to 0x7bff, i.e., all finite ranges
|
||||
let (npassed, nignored) =
|
||||
iterate("f16_exhaustive_equivalence_test", k, 0x7bff, f, g, |i: usize| {
|
||||
let x = f16::from_bits(i as u16 + 1);
|
||||
decode_finite(x)
|
||||
});
|
||||
assert_eq!((npassed, nignored), (29735, 2008));
|
||||
}
|
||||
|
||||
pub fn f32_exhaustive_equivalence_test<F, G>(f: F, g: G, k: usize)
|
||||
where
|
||||
F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit<u8>]) -> Option<(&'a [u8], i16)>,
|
||||
@@ -133,6 +165,17 @@ fn shortest_random_equivalence_test() {
|
||||
|
||||
f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
|
||||
f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
f16_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, n);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(miri, ignore)] // Miri is to slow
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn shortest_f16_exhaustive_equivalence_test() {
|
||||
// see the f32 version
|
||||
use core::num::flt2dec::strategy::dragon::format_shortest as fallback;
|
||||
f16_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -158,6 +201,23 @@ fn shortest_f64_hard_random_equivalence_test() {
|
||||
f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 100_000_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
fn exact_f16_random_equivalence_test() {
|
||||
use core::num::flt2dec::strategy::dragon::format_exact as fallback;
|
||||
// Miri is too slow
|
||||
let n = if cfg!(miri) { 3 } else { 1_000 };
|
||||
|
||||
for k in 1..21 {
|
||||
f16_random_equivalence_test(
|
||||
|d, buf| format_exact_opt(d, buf, i16::MIN),
|
||||
|d, buf| fallback(d, buf, i16::MIN),
|
||||
k,
|
||||
n,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_f32_random_equivalence_test() {
|
||||
use core::num::flt2dec::strategy::dragon::format_exact as fallback;
|
||||
|
||||
@@ -18,6 +18,8 @@ fn test_mul_pow10() {
|
||||
fn shortest_sanity_test() {
|
||||
f64_shortest_sanity_test(format_shortest);
|
||||
f32_shortest_sanity_test(format_shortest);
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
f16_shortest_sanity_test(format_shortest);
|
||||
more_shortest_sanity_test(format_shortest);
|
||||
}
|
||||
|
||||
@@ -41,6 +43,9 @@ fn exact_sanity_test() {
|
||||
f64_exact_sanity_test(format_exact);
|
||||
}
|
||||
f32_exact_sanity_test(format_exact);
|
||||
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
f16_exact_sanity_test(format_exact);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -38,6 +38,8 @@ fn test_max_pow10_no_more_than() {
|
||||
fn shortest_sanity_test() {
|
||||
f64_shortest_sanity_test(format_shortest);
|
||||
f32_shortest_sanity_test(format_shortest);
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
f16_shortest_sanity_test(format_shortest);
|
||||
more_shortest_sanity_test(format_shortest);
|
||||
}
|
||||
|
||||
@@ -50,6 +52,8 @@ fn exact_sanity_test() {
|
||||
f64_exact_sanity_test(format_exact);
|
||||
}
|
||||
f32_exact_sanity_test(format_exact);
|
||||
#[cfg(target_has_reliable_f16)]
|
||||
f16_exact_sanity_test(format_exact);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user