mirror of https://github.com/rust-lang/rust.git
131 lines
5.6 KiB
Rust
131 lines
5.6 KiB
Rust
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)
|
|
}
|
|
|
|
fn compute_float64(q: i64, w: u64) -> (i32, u64) {
|
|
let fp = compute_float::<f64>(q, w);
|
|
(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() {
|
|
// the maximum integer that cna be converted to a `f32` without lost precision.
|
|
let val = 1 << 24;
|
|
let scale = 10_u64.pow(10);
|
|
|
|
// 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, (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));
|
|
assert_eq!(compute_float32(38, 4), (f32::INFINITE_POWER, 0)); // infinity
|
|
assert_eq!(compute_float32(20, 3402823470000000000), (f32::INFINITE_POWER - 1, 8388607));
|
|
}
|
|
|
|
#[test]
|
|
fn compute_float_f64_rounding() {
|
|
// The maximum integer that cna be converted to a `f64` without lost precision.
|
|
let val = 1 << 53;
|
|
let scale = 1000;
|
|
|
|
// 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)
|
|
);
|
|
}
|