From 20cf8ca3f7ac0213f64f89f332793ed8d1a04903 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Jun 2025 14:17:28 +0200 Subject: [PATCH 1/5] float tests: use assert_biteq in more places --- library/coretests/tests/floats/f128.rs | 2 + library/coretests/tests/floats/f16.rs | 2 + library/coretests/tests/floats/f32.rs | 2 + library/coretests/tests/floats/f64.rs | 2 + library/coretests/tests/floats/mod.rs | 431 +++++++++++++------------ 5 files changed, 224 insertions(+), 215 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index 01770f119df10..ffa05715b2d53 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -5,6 +5,8 @@ use core::ops::{Add, Div, Mul, Sub}; use std::f128::consts; use std::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + // Note these tolerances make sense around zero, but not for more extreme exponents. /// Default tolerances. Works for values that should be near precise but not exact. Roughly diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 4797573f7d0dd..7e8ce99dbe081 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -4,6 +4,8 @@ use std::f16::consts; use std::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Tolerance for results on the order of 10.0e-2 #[allow(unused)] const TOL_N2: f16 = 0.0001; diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 4e6509ead2ba8..460aecaac6470 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -2,6 +2,8 @@ use core::f32; use core::f32::consts; use core::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Smallest number const TINY_BITS: u32 = 0x1; diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 74202a3740916..1dfce22c14afe 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -2,6 +2,8 @@ use core::f64; use core::f64::consts; use core::num::FpCategory as Fp; +use super::{assert_approx_eq, assert_biteq}; + /// Smallest number const TINY_BITS: u64 = 0x1; diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index f9b6c85f87105..a2b0d6caf13e9 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -2,7 +2,7 @@ use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; /// Verify that floats are within a tolerance of each other, 1.0e-6 by default. -macro_rules! assert_approx_eq { +macro_rules! assert_approx_eq_ { ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); @@ -14,10 +14,11 @@ macro_rules! assert_approx_eq { ); }}; } +pub(crate) use assert_approx_eq_ as assert_approx_eq; /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq { +macro_rules! assert_biteq_ { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ let l = $left; let r = $right; @@ -41,17 +42,19 @@ macro_rules! assert_biteq { if !l.is_nan() && !r.is_nan() { // Also check that standard equality holds, since most tests use `assert_biteq` rather // than `assert_eq`. - assert_eq!(l, r) + assert_eq!(l, r); } }}; ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq!(@inner $left, $right, "\n", $($tt)*) + assert_biteq_!(@inner $left, $right, "\n", $($tt)*) }; ($left:expr, $right:expr $(,)?) => { - assert_biteq!(@inner $left, $right, "", "") + assert_biteq_!(@inner $left, $right, "", "") }; } +pub(crate) use assert_biteq_ as assert_biteq; +#[allow(unused)] mod const_asserts { // Shadow some assert implementations that would otherwise not compile in a const-context. // Every macro added here also needs to be added in the `float_test!` macro below. @@ -63,8 +66,43 @@ mod const_asserts { std::assert!($left == $right, $($arg)+) }; } - pub(crate) use assert_eq; + + macro_rules! assert_biteq { + (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ + let l = $left; + let r = $right; + + // Hack to coerce left and right to the same type + let mut _eq_ty = l; + _eq_ty = r; + + assert!(l.to_bits() == r.to_bits()); + + if !l.is_nan() && !r.is_nan() { + // Also check that standard equality holds, since most tests use `assert_biteq` rather + // than `assert_eq`. + assert!(l == r); + } + }}; + ($left:expr, $right:expr , $($tt:tt)*) => { + assert_biteq!(@inner $left, $right, "\n", $($tt)*) + }; + ($left:expr, $right:expr $(,)?) => { + assert_biteq!(@inner $left, $right, "", "") + }; + } + pub(crate) use assert_biteq; + + macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!(diff <= $lim); + }}; + } + pub(crate) use assert_approx_eq; } /// Generate float tests for all our float types, for compile-time and run-time behavior. @@ -101,6 +139,8 @@ macro_rules! float_test { test<$fty:ident> $test:block ) => { mod $name { + use super::*; + #[test] $( $( #[$f16_meta] )+ )? fn test_f16() { @@ -131,7 +171,8 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { - use $crate::floats::const_asserts::assert_eq; + #[allow(unused)] + use $crate::floats::const_asserts::{assert_eq, assert_biteq, assert_approx_eq}; #[test] $( $( #[$f16_const_meta] )+ )? @@ -196,29 +237,25 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).min(0.0), 0.0); - assert!((0.0 as Float).min(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).min(-0.0), -0.0); - assert!((-0.0 as Float).min(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).min(9.0), 9.0); - assert_eq!((-9.0 as Float).min(0.0), -9.0); - assert_eq!((0.0 as Float).min(9.0), 0.0); - assert!((0.0 as Float).min(9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).min(9.0), -0.0); - assert!((-0.0 as Float).min(9.0).is_sign_negative()); - assert_eq!((-0.0 as Float).min(-9.0), -9.0); - assert_eq!(Float::INFINITY.min(9.0), 9.0); - assert_eq!((9.0 as Float).min(Float::INFINITY), 9.0); - assert_eq!(Float::INFINITY.min(-9.0), -9.0); - assert_eq!((-9.0 as Float).min(Float::INFINITY), -9.0); - assert_eq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); - assert_eq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); - assert_eq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NAN.min(9.0), 9.0); - assert_eq!(Float::NAN.min(-9.0), -9.0); - assert_eq!((9.0 as Float).min(Float::NAN), 9.0); - assert_eq!((-9.0 as Float).min(Float::NAN), -9.0); + assert_biteq!((0.0 as Float).min(0.0), 0.0); + assert_biteq!((-0.0 as Float).min(-0.0), -0.0); + assert_biteq!((9.0 as Float).min(9.0), 9.0); + assert_biteq!((-9.0 as Float).min(0.0), -9.0); + assert_biteq!((0.0 as Float).min(9.0), 0.0); + assert_biteq!((-0.0 as Float).min(9.0), -0.0); + assert_biteq!((-0.0 as Float).min(-9.0), -9.0); + assert_biteq!(Float::INFINITY.min(9.0), 9.0); + assert_biteq!((9.0 as Float).min(Float::INFINITY), 9.0); + assert_biteq!(Float::INFINITY.min(-9.0), -9.0); + assert_biteq!((-9.0 as Float).min(Float::INFINITY), -9.0); + assert_biteq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); + assert_biteq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); + assert_biteq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NAN.min(9.0), 9.0); + assert_biteq!(Float::NAN.min(-9.0), -9.0); + assert_biteq!((9.0 as Float).min(Float::NAN), 9.0); + assert_biteq!((-9.0 as Float).min(Float::NAN), -9.0); assert!(Float::NAN.min(Float::NAN).is_nan()); } } @@ -230,32 +267,26 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).max(0.0), 0.0); - assert!((0.0 as Float).max(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).max(-0.0), -0.0); - assert!((-0.0 as Float).max(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).max(9.0), 9.0); - assert_eq!((-9.0 as Float).max(0.0), 0.0); - assert!((-9.0 as Float).max(0.0).is_sign_positive()); - assert_eq!((-9.0 as Float).max(-0.0), -0.0); - assert!((-9.0 as Float).max(-0.0).is_sign_negative()); - assert_eq!((0.0 as Float).max(9.0), 9.0); - assert_eq!((0.0 as Float).max(-9.0), 0.0); - assert!((0.0 as Float).max(-9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).max(-9.0), -0.0); - assert!((-0.0 as Float).max(-9.0).is_sign_negative()); - assert_eq!(Float::INFINITY.max(9.0), Float::INFINITY); - assert_eq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::INFINITY.max(-9.0), Float::INFINITY); - assert_eq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.max(9.0), 9.0); - assert_eq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); - assert_eq!(Float::NEG_INFINITY.max(-9.0), -9.0); - assert_eq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); - assert_eq!(Float::NAN.max(9.0), 9.0); - assert_eq!(Float::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as Float).max(Float::NAN), 9.0); - assert_eq!((-9.0 as Float).max(Float::NAN), -9.0); + assert_biteq!((0.0 as Float).max(0.0), 0.0); + assert_biteq!((-0.0 as Float).max(-0.0), -0.0); + assert_biteq!((9.0 as Float).max(9.0), 9.0); + assert_biteq!((-9.0 as Float).max(0.0), 0.0); + assert_biteq!((-9.0 as Float).max(-0.0), -0.0); + assert_biteq!((0.0 as Float).max(9.0), 9.0); + assert_biteq!((0.0 as Float).max(-9.0), 0.0); + assert_biteq!((-0.0 as Float).max(-9.0), -0.0); + assert_biteq!(Float::INFINITY.max(9.0), Float::INFINITY); + assert_biteq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::INFINITY.max(-9.0), Float::INFINITY); + assert_biteq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.max(9.0), 9.0); + assert_biteq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); + assert_biteq!(Float::NEG_INFINITY.max(-9.0), -9.0); + assert_biteq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); + assert_biteq!(Float::NAN.max(9.0), 9.0); + assert_biteq!(Float::NAN.max(-9.0), -9.0); + assert_biteq!((9.0 as Float).max(Float::NAN), 9.0); + assert_biteq!((-9.0 as Float).max(Float::NAN), -9.0); assert!(Float::NAN.max(Float::NAN).is_nan()); } } @@ -267,27 +298,22 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).minimum(0.0), 0.0); - assert!((0.0 as Float).minimum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).minimum(0.0), -0.0); - assert!((-0.0 as Float).minimum(0.0).is_sign_negative()); - assert_eq!((-0.0 as Float).minimum(-0.0), -0.0); - assert!((-0.0 as Float).minimum(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).minimum(9.0), 9.0); - assert_eq!((-9.0 as Float).minimum(0.0), -9.0); - assert_eq!((0.0 as Float).minimum(9.0), 0.0); - assert!((0.0 as Float).minimum(9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).minimum(9.0), -0.0); - assert!((-0.0 as Float).minimum(9.0).is_sign_negative()); - assert_eq!((-0.0 as Float).minimum(-9.0), -9.0); - assert_eq!(Float::INFINITY.minimum(9.0), 9.0); - assert_eq!((9.0 as Float).minimum(Float::INFINITY), 9.0); - assert_eq!(Float::INFINITY.minimum(-9.0), -9.0); - assert_eq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); - assert_eq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); - assert_eq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); - assert_eq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!((0.0 as Float).minimum(0.0), 0.0); + assert_biteq!((-0.0 as Float).minimum(0.0), -0.0); + assert_biteq!((-0.0 as Float).minimum(-0.0), -0.0); + assert_biteq!((9.0 as Float).minimum(9.0), 9.0); + assert_biteq!((-9.0 as Float).minimum(0.0), -9.0); + assert_biteq!((0.0 as Float).minimum(9.0), 0.0); + assert_biteq!((-0.0 as Float).minimum(9.0), -0.0); + assert_biteq!((-0.0 as Float).minimum(-9.0), -9.0); + assert_biteq!(Float::INFINITY.minimum(9.0), 9.0); + assert_biteq!((9.0 as Float).minimum(Float::INFINITY), 9.0); + assert_biteq!(Float::INFINITY.minimum(-9.0), -9.0); + assert_biteq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); + assert_biteq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); + assert_biteq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); + assert_biteq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); assert!(Float::NAN.minimum(9.0).is_nan()); assert!(Float::NAN.minimum(-9.0).is_nan()); assert!((9.0 as Float).minimum(Float::NAN).is_nan()); @@ -303,30 +329,23 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).maximum(0.0), 0.0); - assert!((0.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(0.0), 0.0); - assert!((-0.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(-0.0), -0.0); - assert!((-0.0 as Float).maximum(-0.0).is_sign_negative()); - assert_eq!((9.0 as Float).maximum(9.0), 9.0); - assert_eq!((-9.0 as Float).maximum(0.0), 0.0); - assert!((-9.0 as Float).maximum(0.0).is_sign_positive()); - assert_eq!((-9.0 as Float).maximum(-0.0), -0.0); - assert!((-9.0 as Float).maximum(-0.0).is_sign_negative()); - assert_eq!((0.0 as Float).maximum(9.0), 9.0); - assert_eq!((0.0 as Float).maximum(-9.0), 0.0); - assert!((0.0 as Float).maximum(-9.0).is_sign_positive()); - assert_eq!((-0.0 as Float).maximum(-9.0), -0.0); - assert!((-0.0 as Float).maximum(-9.0).is_sign_negative()); - assert_eq!(Float::INFINITY.maximum(9.0), Float::INFINITY); - assert_eq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); - assert_eq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.maximum(9.0), 9.0); - assert_eq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); - assert_eq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); - assert_eq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); + assert_biteq!((0.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(-0.0), -0.0); + assert_biteq!((9.0 as Float).maximum(9.0), 9.0); + assert_biteq!((-9.0 as Float).maximum(0.0), 0.0); + assert_biteq!((-9.0 as Float).maximum(-0.0), -0.0); + assert_biteq!((0.0 as Float).maximum(9.0), 9.0); + assert_biteq!((0.0 as Float).maximum(-9.0), 0.0); + assert_biteq!((-0.0 as Float).maximum(-9.0), -0.0); + assert_biteq!(Float::INFINITY.maximum(9.0), Float::INFINITY); + assert_biteq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); + assert_biteq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.maximum(9.0), 9.0); + assert_biteq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); + assert_biteq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); + assert_biteq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); assert!(Float::NAN.maximum(9.0).is_nan()); assert!(Float::NAN.maximum(-9.0).is_nan()); assert!((9.0 as Float).maximum(Float::NAN).is_nan()); @@ -342,38 +361,38 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.5 as Float).midpoint(0.5), 0.5); - assert_eq!((0.5 as Float).midpoint(2.5), 1.5); - assert_eq!((3.0 as Float).midpoint(4.0), 3.5); - assert_eq!((-3.0 as Float).midpoint(4.0), 0.5); - assert_eq!((3.0 as Float).midpoint(-4.0), -0.5); - assert_eq!((-3.0 as Float).midpoint(-4.0), -3.5); - assert_eq!((0.0 as Float).midpoint(0.0), 0.0); - assert_eq!((-0.0 as Float).midpoint(-0.0), -0.0); - assert_eq!((-5.0 as Float).midpoint(5.0), 0.0); - assert_eq!(Float::MAX.midpoint(Float::MIN), 0.0); - assert_eq!(Float::MIN.midpoint(Float::MAX), -0.0); - assert_eq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); - assert_eq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); - assert_eq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); - assert_eq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); - assert_eq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); - assert_eq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); - assert_eq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); - assert_eq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); - assert_eq!(Float::MAX.midpoint(Float::MAX), Float::MAX); - assert_eq!( + assert_biteq!((0.5 as Float).midpoint(0.5), 0.5); + assert_biteq!((0.5 as Float).midpoint(2.5), 1.5); + assert_biteq!((3.0 as Float).midpoint(4.0), 3.5); + assert_biteq!((-3.0 as Float).midpoint(4.0), 0.5); + assert_biteq!((3.0 as Float).midpoint(-4.0), -0.5); + assert_biteq!((-3.0 as Float).midpoint(-4.0), -3.5); + assert_biteq!((0.0 as Float).midpoint(0.0), 0.0); + assert_biteq!((-0.0 as Float).midpoint(-0.0), -0.0); + assert_biteq!((-5.0 as Float).midpoint(5.0), 0.0); + assert_biteq!(Float::MAX.midpoint(Float::MIN), 0.0); + assert_biteq!(Float::MIN.midpoint(Float::MAX), 0.0); + assert_biteq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); + assert_biteq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_biteq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); + assert_biteq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_biteq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_biteq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_biteq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_biteq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_biteq!(Float::MAX.midpoint(Float::MAX), Float::MAX); + assert_biteq!( (Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE), Float::MIN_POSITIVE ); - assert_eq!( + assert_biteq!( (-Float::MIN_POSITIVE).midpoint(-Float::MIN_POSITIVE), -Float::MIN_POSITIVE ); - assert_eq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); - assert_eq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); - assert_eq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); - assert_eq!( + assert_biteq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); + assert_biteq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); + assert_biteq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); + assert_biteq!( Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), Float::NEG_INFINITY ); @@ -410,7 +429,7 @@ float_test! { let naive = (large + small) / 2.0; let midpoint = large.midpoint(small); - assert_eq!(naive, midpoint); + assert_biteq!(naive, midpoint); } } } @@ -423,10 +442,10 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((-1.0 as Float).abs(), 1.0); - assert_eq!((1.0 as Float).abs(), 1.0); - assert_eq!(Float::NEG_INFINITY.abs(), Float::INFINITY); - assert_eq!(Float::INFINITY.abs(), Float::INFINITY); + assert_biteq!((-1.0 as Float).abs(), 1.0); + assert_biteq!((1.0 as Float).abs(), 1.0); + assert_biteq!(Float::NEG_INFINITY.abs(), Float::INFINITY); + assert_biteq!(Float::INFINITY.abs(), Float::INFINITY); } } @@ -437,10 +456,10 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((1.0 as Float).copysign(-2.0), -1.0); - assert_eq!((-1.0 as Float).copysign(2.0), 1.0); - assert_eq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); - assert_eq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); + assert_biteq!((1.0 as Float).copysign(-2.0), -1.0); + assert_biteq!((-1.0 as Float).copysign(2.0), 1.0); + assert_biteq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); + assert_biteq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); } } @@ -453,7 +472,7 @@ float_test! { }, test { assert!(Float::INFINITY.rem_euclid(42.0 as Float).is_nan()); - assert_eq!((42.0 as Float).rem_euclid(Float::INFINITY), (42.0 as Float)); + assert_biteq!((42.0 as Float).rem_euclid(Float::INFINITY), 42.0 as Float); assert!((42.0 as Float).rem_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.rem_euclid(Float::INFINITY).is_nan()); assert!(Float::INFINITY.rem_euclid(Float::NAN).is_nan()); @@ -469,7 +488,7 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); + assert_biteq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); assert!((42.0 as Float).div_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); assert!(Float::INFINITY.div_euclid(Float::NAN).is_nan()); @@ -484,20 +503,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).floor(), 0.0); - assert!((0.0 as Float).floor().is_sign_positive()); - assert_eq!((-0.0 as Float).floor(), -0.0); - assert!((-0.0 as Float).floor().is_sign_negative()); - assert_eq!((0.5 as Float).floor(), 0.0); - assert_eq!((-0.5 as Float).floor(), -1.0); - assert_eq!((1.5 as Float).floor(), 1.0); - assert_eq!(Float::MAX.floor(), Float::MAX); - assert_eq!(Float::MIN.floor(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.floor(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).floor(), -1.0); + assert_biteq!((0.0 as Float).floor(), 0.0); + assert_biteq!((-0.0 as Float).floor(), -0.0); + assert_biteq!((0.5 as Float).floor(), 0.0); + assert_biteq!((-0.5 as Float).floor(), -1.0); + assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!(Float::MAX.floor(), Float::MAX); + assert_biteq!(Float::MIN.floor(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.floor(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).floor(), -1.0); assert!(Float::NAN.floor().is_nan()); - assert_eq!(Float::INFINITY.floor(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.floor(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); } } @@ -508,19 +525,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).ceil(), 0.0); - assert!((0.0 as Float).ceil().is_sign_positive()); - assert_eq!((-0.0 as Float).ceil(), 0.0); - assert!((-0.0 as Float).ceil().is_sign_negative()); - assert_eq!((0.5 as Float).ceil(), 1.0); - assert_eq!((-0.5 as Float).ceil(), 0.0); - assert_eq!(Float::MAX.ceil(), Float::MAX); - assert_eq!(Float::MIN.ceil(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.ceil(), 1.0); - assert_eq!((-Float::MIN_POSITIVE).ceil(), 0.0); + assert_biteq!((0.0 as Float).ceil(), 0.0); + assert_biteq!((-0.0 as Float).ceil(), -0.0); + assert_biteq!((0.5 as Float).ceil(), 1.0); + assert_biteq!((-0.5 as Float).ceil(), -0.0); + assert_biteq!(Float::MAX.ceil(), Float::MAX); + assert_biteq!(Float::MIN.ceil(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.ceil(), 1.0); + assert_biteq!((-Float::MIN_POSITIVE).ceil(), -0.0); assert!(Float::NAN.ceil().is_nan()); - assert_eq!(Float::INFINITY.ceil(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.ceil(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); } } @@ -531,19 +546,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).round(), 0.0); - assert!((0.0 as Float).round().is_sign_positive()); - assert_eq!((-0.0 as Float).round(), -0.0); - assert!((-0.0 as Float).round().is_sign_negative()); - assert_eq!((0.5 as Float).round(), 1.0); - assert_eq!((-0.5 as Float).round(), -1.0); - assert_eq!(Float::MAX.round(), Float::MAX); - assert_eq!(Float::MIN.round(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.round(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).round(), 0.0); + assert_biteq!((0.0 as Float).round(), 0.0); + assert_biteq!((-0.0 as Float).round(), -0.0); + assert_biteq!((0.5 as Float).round(), 1.0); + assert_biteq!((-0.5 as Float).round(), -1.0); + assert_biteq!(Float::MAX.round(), Float::MAX); + assert_biteq!(Float::MIN.round(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.round(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).round(), -0.0); assert!(Float::NAN.round().is_nan()); - assert_eq!(Float::INFINITY.round(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.round(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); } } @@ -554,21 +567,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).round_ties_even(), 0.0); - assert!((0.0 as Float).round_ties_even().is_sign_positive()); - assert_eq!((-0.0 as Float).round_ties_even(), -0.0); - assert!((-0.0 as Float).round_ties_even().is_sign_negative()); - assert_eq!((0.5 as Float).round_ties_even(), 0.0); - assert!((0.5 as Float).round_ties_even().is_sign_positive()); - assert_eq!((-0.5 as Float).round_ties_even(), -0.0); - assert!((-0.5 as Float).round_ties_even().is_sign_negative()); - assert_eq!(Float::MAX.round_ties_even(), Float::MAX); - assert_eq!(Float::MIN.round_ties_even(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).round_ties_even(), 0.0); + assert_biteq!((0.0 as Float).round_ties_even(), 0.0); + assert_biteq!((-0.0 as Float).round_ties_even(), -0.0); + assert_biteq!((0.5 as Float).round_ties_even(), 0.0); + assert_biteq!((-0.5 as Float).round_ties_even(), -0.0); + assert_biteq!(Float::MAX.round_ties_even(), Float::MAX); + assert_biteq!(Float::MIN.round_ties_even(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).round_ties_even(), -0.0); assert!(Float::NAN.round_ties_even().is_nan()); - assert_eq!(Float::INFINITY.round_ties_even(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.round_ties_even(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); } } @@ -579,21 +588,17 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).trunc(), 0.0); - assert!((0.0 as Float).trunc().is_sign_positive()); - assert_eq!((-0.0 as Float).trunc(), -0.0); - assert!((-0.0 as Float).trunc().is_sign_negative()); - assert_eq!((0.5 as Float).trunc(), 0.0); - assert!((0.5 as Float).trunc().is_sign_positive()); - assert_eq!((-0.5 as Float).trunc(), -0.0); - assert!((-0.5 as Float).trunc().is_sign_negative()); - assert_eq!(Float::MAX.trunc(), Float::MAX); - assert_eq!(Float::MIN.trunc(), Float::MIN); - assert_eq!(Float::MIN_POSITIVE.trunc(), 0.0); - assert_eq!((-Float::MIN_POSITIVE).trunc(), 0.0); + assert_biteq!((0.0 as Float).trunc(), 0.0); + assert_biteq!((-0.0 as Float).trunc(), -0.0); + assert_biteq!((0.5 as Float).trunc(), 0.0); + assert_biteq!((-0.5 as Float).trunc(), -0.0); + assert_biteq!(Float::MAX.trunc(), Float::MAX); + assert_biteq!(Float::MIN.trunc(), Float::MIN); + assert_biteq!(Float::MIN_POSITIVE.trunc(), 0.0); + assert_biteq!((-Float::MIN_POSITIVE).trunc(), -0.0); assert!(Float::NAN.trunc().is_nan()); - assert_eq!(Float::INFINITY.trunc(), Float::INFINITY); - assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); + assert_biteq!(Float::INFINITY.trunc(), Float::INFINITY); + assert_biteq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); } } @@ -604,19 +609,15 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { - assert_eq!((0.0 as Float).fract(), 0.0); - assert!((0.0 as Float).fract().is_sign_positive()); - assert_eq!((-0.0 as Float).fract(), 0.0); - assert!((-0.0 as Float).fract().is_sign_positive()); - assert_eq!((0.5 as Float).fract(), 0.5); - assert!((0.5 as Float).fract().is_sign_positive()); - assert_eq!((-0.5 as Float).fract(), -0.5); - assert!((-0.5 as Float).fract().is_sign_negative()); - assert_eq!(Float::MAX.fract(), 0.0); - assert_eq!(Float::MIN.fract(), 0.0); - assert_eq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); + assert_biteq!((0.0 as Float).fract(), 0.0); + assert_biteq!((-0.0 as Float).fract(), 0.0); + assert_biteq!((0.5 as Float).fract(), 0.5); + assert_biteq!((-0.5 as Float).fract(), -0.5); + assert_biteq!(Float::MAX.fract(), 0.0); + assert_biteq!(Float::MIN.fract(), 0.0); + assert_biteq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); assert!(Float::MIN_POSITIVE.fract().is_sign_positive()); - assert_eq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); + assert_biteq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); assert!((-Float::MIN_POSITIVE).fract().is_sign_negative()); assert!(Float::NAN.fract().is_nan()); assert!(Float::INFINITY.fract().is_nan()); From 79cb013b55d4b7ba02a5ee0fd5436c2f62a199f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Jun 2025 14:17:50 +0200 Subject: [PATCH 2/5] float tests: deduplicate min, max, and rounding tests --- library/coretests/tests/floats/f128.rs | 120 ------------------------- library/coretests/tests/floats/f16.rs | 120 ------------------------- library/coretests/tests/floats/f32.rs | 110 ----------------------- library/coretests/tests/floats/f64.rs | 98 -------------------- library/coretests/tests/floats/mod.rs | 64 +++++++++++-- 5 files changed, 56 insertions(+), 456 deletions(-) diff --git a/library/coretests/tests/floats/f128.rs b/library/coretests/tests/floats/f128.rs index ffa05715b2d53..cf78e8796a030 100644 --- a/library/coretests/tests/floats/f128.rs +++ b/library/coretests/tests/floats/f128.rs @@ -55,34 +55,6 @@ fn test_num_f128() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_min_nan() { - assert_biteq!(f128::NAN.min(2.0), 2.0); - assert_biteq!(2.0f128.min(f128::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_max_nan() { - assert_biteq!(f128::NAN.max(2.0), 2.0); - assert_biteq!(2.0f128.max(f128::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_minimum() { - assert!(f128::NAN.minimum(2.0).is_nan()); - assert!(2.0f128.minimum(f128::NAN).is_nan()); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_maximum() { - assert!(f128::NAN.maximum(2.0).is_nan()); - assert!(2.0f128.maximum(f128::NAN).is_nan()); -} - #[test] fn test_nan() { let nan: f128 = f128::NAN; @@ -234,98 +206,6 @@ fn test_classify() { assert_eq!(1e-4932f128.classify(), Fp::Subnormal); } -#[test] -#[cfg(target_has_reliable_f128_math)] -fn test_floor() { - assert_biteq!(1.0f128.floor(), 1.0f128); - assert_biteq!(1.3f128.floor(), 1.0f128); - assert_biteq!(1.5f128.floor(), 1.0f128); - assert_biteq!(1.7f128.floor(), 1.0f128); - assert_biteq!(0.0f128.floor(), 0.0f128); - assert_biteq!((-0.0f128).floor(), -0.0f128); - assert_biteq!((-1.0f128).floor(), -1.0f128); - assert_biteq!((-1.3f128).floor(), -2.0f128); - assert_biteq!((-1.5f128).floor(), -2.0f128); - assert_biteq!((-1.7f128).floor(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_ceil() { - assert_biteq!(1.0f128.ceil(), 1.0f128); - assert_biteq!(1.3f128.ceil(), 2.0f128); - assert_biteq!(1.5f128.ceil(), 2.0f128); - assert_biteq!(1.7f128.ceil(), 2.0f128); - assert_biteq!(0.0f128.ceil(), 0.0f128); - assert_biteq!((-0.0f128).ceil(), -0.0f128); - assert_biteq!((-1.0f128).ceil(), -1.0f128); - assert_biteq!((-1.3f128).ceil(), -1.0f128); - assert_biteq!((-1.5f128).ceil(), -1.0f128); - assert_biteq!((-1.7f128).ceil(), -1.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_round() { - assert_biteq!(2.5f128.round(), 3.0f128); - assert_biteq!(1.0f128.round(), 1.0f128); - assert_biteq!(1.3f128.round(), 1.0f128); - assert_biteq!(1.5f128.round(), 2.0f128); - assert_biteq!(1.7f128.round(), 2.0f128); - assert_biteq!(0.0f128.round(), 0.0f128); - assert_biteq!((-0.0f128).round(), -0.0f128); - assert_biteq!((-1.0f128).round(), -1.0f128); - assert_biteq!((-1.3f128).round(), -1.0f128); - assert_biteq!((-1.5f128).round(), -2.0f128); - assert_biteq!((-1.7f128).round(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_round_ties_even() { - assert_biteq!(2.5f128.round_ties_even(), 2.0f128); - assert_biteq!(1.0f128.round_ties_even(), 1.0f128); - assert_biteq!(1.3f128.round_ties_even(), 1.0f128); - assert_biteq!(1.5f128.round_ties_even(), 2.0f128); - assert_biteq!(1.7f128.round_ties_even(), 2.0f128); - assert_biteq!(0.0f128.round_ties_even(), 0.0f128); - assert_biteq!((-0.0f128).round_ties_even(), -0.0f128); - assert_biteq!((-1.0f128).round_ties_even(), -1.0f128); - assert_biteq!((-1.3f128).round_ties_even(), -1.0f128); - assert_biteq!((-1.5f128).round_ties_even(), -2.0f128); - assert_biteq!((-1.7f128).round_ties_even(), -2.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_trunc() { - assert_biteq!(1.0f128.trunc(), 1.0f128); - assert_biteq!(1.3f128.trunc(), 1.0f128); - assert_biteq!(1.5f128.trunc(), 1.0f128); - assert_biteq!(1.7f128.trunc(), 1.0f128); - assert_biteq!(0.0f128.trunc(), 0.0f128); - assert_biteq!((-0.0f128).trunc(), -0.0f128); - assert_biteq!((-1.0f128).trunc(), -1.0f128); - assert_biteq!((-1.3f128).trunc(), -1.0f128); - assert_biteq!((-1.5f128).trunc(), -1.0f128); - assert_biteq!((-1.7f128).trunc(), -1.0f128); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f128_math))] -fn test_fract() { - assert_biteq!(1.0f128.fract(), 0.0f128); - assert_biteq!(1.3f128.fract(), 0.300000000000000000000000000000000039f128); - assert_biteq!(1.5f128.fract(), 0.5f128); - assert_biteq!(1.7f128.fract(), 0.7f128); - assert_biteq!(0.0f128.fract(), 0.0f128); - assert_biteq!((-0.0f128).fract(), 0.0f128); - assert_biteq!((-1.0f128).fract(), 0.0f128); - assert_biteq!((-1.3f128).fract(), -0.300000000000000000000000000000000039f128); - assert_biteq!((-1.5f128).fract(), -0.5f128); - assert_biteq!((-1.7f128).fract(), -0.699999999999999999999999999999999961f128); -} - #[test] #[cfg(any(miri, target_has_reliable_f128_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f16.rs b/library/coretests/tests/floats/f16.rs index 7e8ce99dbe081..9e91b654304b6 100644 --- a/library/coretests/tests/floats/f16.rs +++ b/library/coretests/tests/floats/f16.rs @@ -51,34 +51,6 @@ fn test_num_f16() { // FIXME(f16_f128,miri): many of these have to be disabled since miri does not yet support // the intrinsics. -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_min_nan() { - assert_biteq!(f16::NAN.min(2.0), 2.0); - assert_biteq!(2.0f16.min(f16::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_max_nan() { - assert_biteq!(f16::NAN.max(2.0), 2.0); - assert_biteq!(2.0f16.max(f16::NAN), 2.0); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_minimum() { - assert!(f16::NAN.minimum(2.0).is_nan()); - assert!(2.0f16.minimum(f16::NAN).is_nan()); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_maximum() { - assert!(f16::NAN.maximum(2.0).is_nan()); - assert!(2.0f16.maximum(f16::NAN).is_nan()); -} - #[test] fn test_nan() { let nan: f16 = f16::NAN; @@ -230,98 +202,6 @@ fn test_classify() { assert_eq!(1e-5f16.classify(), Fp::Subnormal); } -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_floor() { - assert_biteq!(1.0f16.floor(), 1.0f16); - assert_biteq!(1.3f16.floor(), 1.0f16); - assert_biteq!(1.5f16.floor(), 1.0f16); - assert_biteq!(1.7f16.floor(), 1.0f16); - assert_biteq!(0.0f16.floor(), 0.0f16); - assert_biteq!((-0.0f16).floor(), -0.0f16); - assert_biteq!((-1.0f16).floor(), -1.0f16); - assert_biteq!((-1.3f16).floor(), -2.0f16); - assert_biteq!((-1.5f16).floor(), -2.0f16); - assert_biteq!((-1.7f16).floor(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_ceil() { - assert_biteq!(1.0f16.ceil(), 1.0f16); - assert_biteq!(1.3f16.ceil(), 2.0f16); - assert_biteq!(1.5f16.ceil(), 2.0f16); - assert_biteq!(1.7f16.ceil(), 2.0f16); - assert_biteq!(0.0f16.ceil(), 0.0f16); - assert_biteq!((-0.0f16).ceil(), -0.0f16); - assert_biteq!((-1.0f16).ceil(), -1.0f16); - assert_biteq!((-1.3f16).ceil(), -1.0f16); - assert_biteq!((-1.5f16).ceil(), -1.0f16); - assert_biteq!((-1.7f16).ceil(), -1.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_round() { - assert_biteq!(2.5f16.round(), 3.0f16); - assert_biteq!(1.0f16.round(), 1.0f16); - assert_biteq!(1.3f16.round(), 1.0f16); - assert_biteq!(1.5f16.round(), 2.0f16); - assert_biteq!(1.7f16.round(), 2.0f16); - assert_biteq!(0.0f16.round(), 0.0f16); - assert_biteq!((-0.0f16).round(), -0.0f16); - assert_biteq!((-1.0f16).round(), -1.0f16); - assert_biteq!((-1.3f16).round(), -1.0f16); - assert_biteq!((-1.5f16).round(), -2.0f16); - assert_biteq!((-1.7f16).round(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_round_ties_even() { - assert_biteq!(2.5f16.round_ties_even(), 2.0f16); - assert_biteq!(1.0f16.round_ties_even(), 1.0f16); - assert_biteq!(1.3f16.round_ties_even(), 1.0f16); - assert_biteq!(1.5f16.round_ties_even(), 2.0f16); - assert_biteq!(1.7f16.round_ties_even(), 2.0f16); - assert_biteq!(0.0f16.round_ties_even(), 0.0f16); - assert_biteq!((-0.0f16).round_ties_even(), -0.0f16); - assert_biteq!((-1.0f16).round_ties_even(), -1.0f16); - assert_biteq!((-1.3f16).round_ties_even(), -1.0f16); - assert_biteq!((-1.5f16).round_ties_even(), -2.0f16); - assert_biteq!((-1.7f16).round_ties_even(), -2.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_trunc() { - assert_biteq!(1.0f16.trunc(), 1.0f16); - assert_biteq!(1.3f16.trunc(), 1.0f16); - assert_biteq!(1.5f16.trunc(), 1.0f16); - assert_biteq!(1.7f16.trunc(), 1.0f16); - assert_biteq!(0.0f16.trunc(), 0.0f16); - assert_biteq!((-0.0f16).trunc(), -0.0f16); - assert_biteq!((-1.0f16).trunc(), -1.0f16); - assert_biteq!((-1.3f16).trunc(), -1.0f16); - assert_biteq!((-1.5f16).trunc(), -1.0f16); - assert_biteq!((-1.7f16).trunc(), -1.0f16); -} - -#[test] -#[cfg(any(miri, target_has_reliable_f16_math))] -fn test_fract() { - assert_biteq!(1.0f16.fract(), 0.0f16); - assert_biteq!(1.3f16.fract(), 0.2998f16); - assert_biteq!(1.5f16.fract(), 0.5f16); - assert_biteq!(1.7f16.fract(), 0.7f16); - assert_biteq!(0.0f16.fract(), 0.0f16); - assert_biteq!((-0.0f16).fract(), 0.0f16); - assert_biteq!((-1.0f16).fract(), 0.0f16); - assert_biteq!((-1.3f16).fract(), -0.2998f16); - assert_biteq!((-1.5f16).fract(), -0.5f16); - assert_biteq!((-1.7f16).fract(), -0.7f16); -} - #[test] #[cfg(any(miri, target_has_reliable_f16_math))] fn test_abs() { diff --git a/library/coretests/tests/floats/f32.rs b/library/coretests/tests/floats/f32.rs index 460aecaac6470..08a16e7c440f2 100644 --- a/library/coretests/tests/floats/f32.rs +++ b/library/coretests/tests/floats/f32.rs @@ -30,30 +30,6 @@ fn test_num_f32() { super::test_num(10f32, 2f32); } -#[test] -fn test_min_nan() { - assert_biteq!(f32::NAN.min(2.0), 2.0); - assert_biteq!(2.0f32.min(f32::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_biteq!(f32::NAN.max(2.0), 2.0); - assert_biteq!(2.0f32.max(f32::NAN), 2.0); -} - -#[test] -fn test_minimum() { - assert!(f32::NAN.minimum(2.0).is_nan()); - assert!(2.0f32.minimum(f32::NAN).is_nan()); -} - -#[test] -fn test_maximum() { - assert!(f32::NAN.maximum(2.0).is_nan()); - assert!(2.0f32.maximum(f32::NAN).is_nan()); -} - #[test] fn test_nan() { let nan: f32 = f32::NAN; @@ -205,92 +181,6 @@ fn test_classify() { assert_eq!(1e-38f32.classify(), Fp::Subnormal); } -#[test] -fn test_floor() { - assert_biteq!(f32::math::floor(1.0f32), 1.0f32); - assert_biteq!(f32::math::floor(1.3f32), 1.0f32); - assert_biteq!(f32::math::floor(1.5f32), 1.0f32); - assert_biteq!(f32::math::floor(1.7f32), 1.0f32); - assert_biteq!(f32::math::floor(0.0f32), 0.0f32); - assert_biteq!(f32::math::floor(-0.0f32), -0.0f32); - assert_biteq!(f32::math::floor(-1.0f32), -1.0f32); - assert_biteq!(f32::math::floor(-1.3f32), -2.0f32); - assert_biteq!(f32::math::floor(-1.5f32), -2.0f32); - assert_biteq!(f32::math::floor(-1.7f32), -2.0f32); -} - -#[test] -fn test_ceil() { - assert_biteq!(f32::math::ceil(1.0f32), 1.0f32); - assert_biteq!(f32::math::ceil(1.3f32), 2.0f32); - assert_biteq!(f32::math::ceil(1.5f32), 2.0f32); - assert_biteq!(f32::math::ceil(1.7f32), 2.0f32); - assert_biteq!(f32::math::ceil(0.0f32), 0.0f32); - assert_biteq!(f32::math::ceil(-0.0f32), -0.0f32); - assert_biteq!(f32::math::ceil(-1.0f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.3f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.5f32), -1.0f32); - assert_biteq!(f32::math::ceil(-1.7f32), -1.0f32); -} - -#[test] -fn test_round() { - assert_biteq!(f32::math::round(2.5f32), 3.0f32); - assert_biteq!(f32::math::round(1.0f32), 1.0f32); - assert_biteq!(f32::math::round(1.3f32), 1.0f32); - assert_biteq!(f32::math::round(1.5f32), 2.0f32); - assert_biteq!(f32::math::round(1.7f32), 2.0f32); - assert_biteq!(f32::math::round(0.0f32), 0.0f32); - assert_biteq!(f32::math::round(-0.0f32), -0.0f32); - assert_biteq!(f32::math::round(-1.0f32), -1.0f32); - assert_biteq!(f32::math::round(-1.3f32), -1.0f32); - assert_biteq!(f32::math::round(-1.5f32), -2.0f32); - assert_biteq!(f32::math::round(-1.7f32), -2.0f32); -} - -#[test] -fn test_round_ties_even() { - assert_biteq!(f32::math::round_ties_even(2.5f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(1.0f32), 1.0f32); - assert_biteq!(f32::math::round_ties_even(1.3f32), 1.0f32); - assert_biteq!(f32::math::round_ties_even(1.5f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(1.7f32), 2.0f32); - assert_biteq!(f32::math::round_ties_even(0.0f32), 0.0f32); - assert_biteq!(f32::math::round_ties_even(-0.0f32), -0.0f32); - assert_biteq!(f32::math::round_ties_even(-1.0f32), -1.0f32); - assert_biteq!(f32::math::round_ties_even(-1.3f32), -1.0f32); - assert_biteq!(f32::math::round_ties_even(-1.5f32), -2.0f32); - assert_biteq!(f32::math::round_ties_even(-1.7f32), -2.0f32); -} - -#[test] -fn test_trunc() { - assert_biteq!(f32::math::trunc(1.0f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.3f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.5f32), 1.0f32); - assert_biteq!(f32::math::trunc(1.7f32), 1.0f32); - assert_biteq!(f32::math::trunc(0.0f32), 0.0f32); - assert_biteq!(f32::math::trunc(-0.0f32), -0.0f32); - assert_biteq!(f32::math::trunc(-1.0f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.3f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.5f32), -1.0f32); - assert_biteq!(f32::math::trunc(-1.7f32), -1.0f32); -} - -#[test] -fn test_fract() { - assert_biteq!(f32::math::fract(1.0f32), 0.0f32); - assert_biteq!(f32::math::fract(1.3f32), 0.29999995f32); - assert_biteq!(f32::math::fract(1.5f32), 0.5f32); - assert_biteq!(f32::math::fract(1.7f32), 0.70000005f32); - assert_biteq!(f32::math::fract(0.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-0.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-1.0f32), 0.0f32); - assert_biteq!(f32::math::fract(-1.3f32), -0.29999995f32); - assert_biteq!(f32::math::fract(-1.5f32), -0.5f32); - assert_biteq!(f32::math::fract(-1.7f32), -0.70000005f32); -} - #[test] fn test_abs() { assert_biteq!(f32::INFINITY.abs(), f32::INFINITY); diff --git a/library/coretests/tests/floats/f64.rs b/library/coretests/tests/floats/f64.rs index 1dfce22c14afe..97abb01bfab72 100644 --- a/library/coretests/tests/floats/f64.rs +++ b/library/coretests/tests/floats/f64.rs @@ -30,18 +30,6 @@ fn test_num_f64() { super::test_num(10f64, 2f64); } -#[test] -fn test_min_nan() { - assert_biteq!(f64::NAN.min(2.0), 2.0); - assert_biteq!(2.0f64.min(f64::NAN), 2.0); -} - -#[test] -fn test_max_nan() { - assert_biteq!(f64::NAN.max(2.0), 2.0); - assert_biteq!(2.0f64.max(f64::NAN), 2.0); -} - #[test] fn test_nan() { let nan: f64 = f64::NAN; @@ -192,92 +180,6 @@ fn test_classify() { assert_eq!(1e-308f64.classify(), Fp::Subnormal); } -#[test] -fn test_floor() { - assert_biteq!(f64::math::floor(1.0f64), 1.0f64); - assert_biteq!(f64::math::floor(1.3f64), 1.0f64); - assert_biteq!(f64::math::floor(1.5f64), 1.0f64); - assert_biteq!(f64::math::floor(1.7f64), 1.0f64); - assert_biteq!(f64::math::floor(0.0f64), 0.0f64); - assert_biteq!(f64::math::floor(-0.0f64), -0.0f64); - assert_biteq!(f64::math::floor(-1.0f64), -1.0f64); - assert_biteq!(f64::math::floor(-1.3f64), -2.0f64); - assert_biteq!(f64::math::floor(-1.5f64), -2.0f64); - assert_biteq!(f64::math::floor(-1.7f64), -2.0f64); -} - -#[test] -fn test_ceil() { - assert_biteq!(f64::math::ceil(1.0f64), 1.0f64); - assert_biteq!(f64::math::ceil(1.3f64), 2.0f64); - assert_biteq!(f64::math::ceil(1.5f64), 2.0f64); - assert_biteq!(f64::math::ceil(1.7f64), 2.0f64); - assert_biteq!(f64::math::ceil(0.0f64), 0.0f64); - assert_biteq!(f64::math::ceil(-0.0f64), -0.0f64); - assert_biteq!(f64::math::ceil(-1.0f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.3f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.5f64), -1.0f64); - assert_biteq!(f64::math::ceil(-1.7f64), -1.0f64); -} - -#[test] -fn test_round() { - assert_biteq!(f64::math::round(2.5f64), 3.0f64); - assert_biteq!(f64::math::round(1.0f64), 1.0f64); - assert_biteq!(f64::math::round(1.3f64), 1.0f64); - assert_biteq!(f64::math::round(1.5f64), 2.0f64); - assert_biteq!(f64::math::round(1.7f64), 2.0f64); - assert_biteq!(f64::math::round(0.0f64), 0.0f64); - assert_biteq!(f64::math::round(-0.0f64), -0.0f64); - assert_biteq!(f64::math::round(-1.0f64), -1.0f64); - assert_biteq!(f64::math::round(-1.3f64), -1.0f64); - assert_biteq!(f64::math::round(-1.5f64), -2.0f64); - assert_biteq!(f64::math::round(-1.7f64), -2.0f64); -} - -#[test] -fn test_round_ties_even() { - assert_biteq!(f64::math::round_ties_even(2.5f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(1.0f64), 1.0f64); - assert_biteq!(f64::math::round_ties_even(1.3f64), 1.0f64); - assert_biteq!(f64::math::round_ties_even(1.5f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(1.7f64), 2.0f64); - assert_biteq!(f64::math::round_ties_even(0.0f64), 0.0f64); - assert_biteq!(f64::math::round_ties_even(-0.0f64), -0.0f64); - assert_biteq!(f64::math::round_ties_even(-1.0f64), -1.0f64); - assert_biteq!(f64::math::round_ties_even(-1.3f64), -1.0f64); - assert_biteq!(f64::math::round_ties_even(-1.5f64), -2.0f64); - assert_biteq!(f64::math::round_ties_even(-1.7f64), -2.0f64); -} - -#[test] -fn test_trunc() { - assert_biteq!(f64::math::trunc(1.0f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.3f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.5f64), 1.0f64); - assert_biteq!(f64::math::trunc(1.7f64), 1.0f64); - assert_biteq!(f64::math::trunc(0.0f64), 0.0f64); - assert_biteq!(f64::math::trunc(-0.0f64), -0.0f64); - assert_biteq!(f64::math::trunc(-1.0f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.3f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.5f64), -1.0f64); - assert_biteq!(f64::math::trunc(-1.7f64), -1.0f64); -} - -#[test] -fn test_fract() { - assert_biteq!(f64::math::fract(1.0f64), 0.0f64); - assert_biteq!(f64::math::fract(1.3f64), 0.30000000000000004f64); - assert_biteq!(f64::math::fract(1.5f64), 0.5f64); - assert_biteq!(f64::math::fract(1.7f64), 0.7f64); - assert_biteq!(f64::math::fract(0.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-0.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-1.0f64), 0.0f64); - assert_biteq!(f64::math::fract(-1.3f64), -0.30000000000000004f64); - assert_biteq!(f64::math::fract(-1.5f64), -0.5f64); - assert_biteq!(f64::math::fract(-1.7f64), -0.69999999999999996f64); -} - #[test] fn test_abs() { assert_biteq!(f64::INFINITY.abs(), f64::INFINITY); diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index a2b0d6caf13e9..c76736803a1ec 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -54,7 +54,6 @@ macro_rules! assert_biteq_ { } pub(crate) use assert_biteq_ as assert_biteq; -#[allow(unused)] mod const_asserts { // Shadow some assert implementations that would otherwise not compile in a const-context. // Every macro added here also needs to be added in the `float_test!` macro below. @@ -503,11 +502,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { + assert_biteq!((1.0 as Float).floor(), 1.0); + assert_biteq!((1.3 as Float).floor(), 1.0); + assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!((1.7 as Float).floor(), 1.0); + assert_biteq!((0.5 as Float).floor(), 0.0); assert_biteq!((0.0 as Float).floor(), 0.0); assert_biteq!((-0.0 as Float).floor(), -0.0); - assert_biteq!((0.5 as Float).floor(), 0.0); assert_biteq!((-0.5 as Float).floor(), -1.0); - assert_biteq!((1.5 as Float).floor(), 1.0); + assert_biteq!((-1.0 as Float).floor(), -1.0); + assert_biteq!((-1.3 as Float).floor(), -2.0); + assert_biteq!((-1.5 as Float).floor(), -2.0); + assert_biteq!((-1.7 as Float).floor(), -2.0); assert_biteq!(Float::MAX.floor(), Float::MAX); assert_biteq!(Float::MIN.floor(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.floor(), 0.0); @@ -525,10 +531,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { + assert_biteq!((1.0 as Float).ceil(), 1.0); + assert_biteq!((1.3 as Float).ceil(), 2.0); + assert_biteq!((1.5 as Float).ceil(), 2.0); + assert_biteq!((1.7 as Float).ceil(), 2.0); + assert_biteq!((0.5 as Float).ceil(), 1.0); assert_biteq!((0.0 as Float).ceil(), 0.0); assert_biteq!((-0.0 as Float).ceil(), -0.0); - assert_biteq!((0.5 as Float).ceil(), 1.0); assert_biteq!((-0.5 as Float).ceil(), -0.0); + assert_biteq!((-1.0 as Float).ceil(), -1.0); + assert_biteq!((-1.3 as Float).ceil(), -1.0); + assert_biteq!((-1.5 as Float).ceil(), -1.0); + assert_biteq!((-1.7 as Float).ceil(), -1.0); assert_biteq!(Float::MAX.ceil(), Float::MAX); assert_biteq!(Float::MIN.ceil(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.ceil(), 1.0); @@ -546,10 +560,19 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { + assert_biteq!((2.5 as Float).round(), 3.0); + assert_biteq!((1.0 as Float).round(), 1.0); + assert_biteq!((1.3 as Float).round(), 1.0); + assert_biteq!((1.5 as Float).round(), 2.0); + assert_biteq!((1.7 as Float).round(), 2.0); + assert_biteq!((0.5 as Float).round(), 1.0); assert_biteq!((0.0 as Float).round(), 0.0); assert_biteq!((-0.0 as Float).round(), -0.0); - assert_biteq!((0.5 as Float).round(), 1.0); assert_biteq!((-0.5 as Float).round(), -1.0); + assert_biteq!((-1.0 as Float).round(), -1.0); + assert_biteq!((-1.3 as Float).round(), -1.0); + assert_biteq!((-1.5 as Float).round(), -2.0); + assert_biteq!((-1.7 as Float).round(), -2.0); assert_biteq!(Float::MAX.round(), Float::MAX); assert_biteq!(Float::MIN.round(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.round(), 0.0); @@ -567,10 +590,19 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { + assert_biteq!((2.5 as Float).round_ties_even(), 2.0); + assert_biteq!((1.0 as Float).round_ties_even(), 1.0); + assert_biteq!((1.3 as Float).round_ties_even(), 1.0); + assert_biteq!((1.5 as Float).round_ties_even(), 2.0); + assert_biteq!((1.7 as Float).round_ties_even(), 2.0); + assert_biteq!((0.5 as Float).round_ties_even(), 0.0); assert_biteq!((0.0 as Float).round_ties_even(), 0.0); assert_biteq!((-0.0 as Float).round_ties_even(), -0.0); - assert_biteq!((0.5 as Float).round_ties_even(), 0.0); assert_biteq!((-0.5 as Float).round_ties_even(), -0.0); + assert_biteq!((-1.0 as Float).round_ties_even(), -1.0); + assert_biteq!((-1.3 as Float).round_ties_even(), -1.0); + assert_biteq!((-1.5 as Float).round_ties_even(), -2.0); + assert_biteq!((-1.7 as Float).round_ties_even(), -2.0); assert_biteq!(Float::MAX.round_ties_even(), Float::MAX); assert_biteq!(Float::MIN.round_ties_even(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); @@ -588,10 +620,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { + assert_biteq!((1.0 as Float).trunc(), 1.0); + assert_biteq!((1.3 as Float).trunc(), 1.0); + assert_biteq!((1.5 as Float).trunc(), 1.0); + assert_biteq!((1.7 as Float).trunc(), 1.0); + assert_biteq!((0.5 as Float).trunc(), 0.0); assert_biteq!((0.0 as Float).trunc(), 0.0); assert_biteq!((-0.0 as Float).trunc(), -0.0); - assert_biteq!((0.5 as Float).trunc(), 0.0); assert_biteq!((-0.5 as Float).trunc(), -0.0); + assert_biteq!((-1.0 as Float).trunc(), -1.0); + assert_biteq!((-1.3 as Float).trunc(), -1.0); + assert_biteq!((-1.5 as Float).trunc(), -1.0); + assert_biteq!((-1.7 as Float).trunc(), -1.0); assert_biteq!(Float::MAX.trunc(), Float::MAX); assert_biteq!(Float::MIN.trunc(), Float::MIN); assert_biteq!(Float::MIN_POSITIVE.trunc(), 0.0); @@ -609,10 +649,18 @@ float_test! { f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, test { + assert_biteq!((1.0 as Float).fract(), 0.0); + assert_approx_eq!((1.3 as Float).fract(), 0.3, 1e-3); // rounding differs between float types + assert_biteq!((1.5 as Float).fract(), 0.5); + assert_approx_eq!((1.7 as Float).fract(), 0.7); + assert_biteq!((0.5 as Float).fract(), 0.5); assert_biteq!((0.0 as Float).fract(), 0.0); assert_biteq!((-0.0 as Float).fract(), 0.0); - assert_biteq!((0.5 as Float).fract(), 0.5); assert_biteq!((-0.5 as Float).fract(), -0.5); + assert_biteq!((-1.0 as Float).fract(), 0.0); + assert_approx_eq!((-1.3 as Float).fract(), -0.3, 1e-3); // rounding differs between float types + assert_biteq!((-1.5 as Float).fract(), -0.5); + assert_approx_eq!((-1.7 as Float).fract(), -0.7); assert_biteq!(Float::MAX.fract(), 0.0); assert_biteq!(Float::MIN.fract(), 0.0); assert_biteq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); From 2766b77f1ed0abec2d50a6d26c9cc4459c551415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Jun 2025 13:51:09 +0200 Subject: [PATCH 3/5] make the default float comparison tolerance type-dependent --- library/coretests/tests/floats/mod.rs | 46 ++++++++++++++++++--------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index c76736803a1ec..6288ff23afeac 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -1,9 +1,32 @@ use std::fmt; use std::ops::{Add, Div, Mul, Rem, Sub}; -/// Verify that floats are within a tolerance of each other, 1.0e-6 by default. +/// Set the default tolerance for float comparison based on the type. +trait Approx { + const LIM: Self; +} + +impl Approx for f16 { + const LIM: Self = 1e-3; +} +impl Approx for f32 { + const LIM: Self = 1e-6; +} +impl Approx for f64 { + const LIM: Self = 1e-6; +} +impl Approx for f128 { + const LIM: Self = 1e-9; +} + +/// Determine the tolerance for values of the argument type. +const fn lim_for_ty(_x: T) -> T { + T::LIM +} + +/// Verify that floats are within a tolerance of each other. macro_rules! assert_approx_eq_ { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -57,15 +80,6 @@ pub(crate) use assert_biteq_ as assert_biteq; mod const_asserts { // Shadow some assert implementations that would otherwise not compile in a const-context. // Every macro added here also needs to be added in the `float_test!` macro below. - macro_rules! assert_eq { - ($left:expr, $right:expr $(,)?) => { - std::assert!($left == $right) - }; - ($left:expr, $right:expr, $($arg:tt)+) => { - std::assert!($left == $right, $($arg)+) - }; - } - pub(crate) use assert_eq; macro_rules! assert_biteq { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ @@ -94,7 +108,7 @@ mod const_asserts { pub(crate) use assert_biteq; macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, 1.0e-6) }}; + ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -171,7 +185,9 @@ macro_rules! float_test { $( $( #[$const_meta] )+ )? mod const_ { #[allow(unused)] - use $crate::floats::const_asserts::{assert_eq, assert_biteq, assert_approx_eq}; + use super::Approx; + #[allow(unused)] + use $crate::floats::const_asserts::{assert_biteq, assert_approx_eq}; #[test] $( $( #[$f16_const_meta] )+ )? @@ -650,7 +666,7 @@ float_test! { }, test { assert_biteq!((1.0 as Float).fract(), 0.0); - assert_approx_eq!((1.3 as Float).fract(), 0.3, 1e-3); // rounding differs between float types + assert_approx_eq!((1.3 as Float).fract(), 0.3); // rounding differs between float types assert_biteq!((1.5 as Float).fract(), 0.5); assert_approx_eq!((1.7 as Float).fract(), 0.7); assert_biteq!((0.5 as Float).fract(), 0.5); @@ -658,7 +674,7 @@ float_test! { assert_biteq!((-0.0 as Float).fract(), 0.0); assert_biteq!((-0.5 as Float).fract(), -0.5); assert_biteq!((-1.0 as Float).fract(), 0.0); - assert_approx_eq!((-1.3 as Float).fract(), -0.3, 1e-3); // rounding differs between float types + assert_approx_eq!((-1.3 as Float).fract(), -0.3); // rounding differs between float types assert_biteq!((-1.5 as Float).fract(), -0.5); assert_approx_eq!((-1.7 as Float).fract(), -0.7); assert_biteq!(Float::MAX.fract(), 0.0); From 1b6bb4566d15448e9d76bbd1716f2153fb04efff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Jun 2025 14:05:24 +0200 Subject: [PATCH 4/5] float midpoint tests: add missing NAN cases --- library/coretests/tests/floats/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 6288ff23afeac..8f15a2625af07 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -411,6 +411,8 @@ float_test! { Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), Float::NEG_INFINITY ); + assert!(Float::NEG_INFINITY.midpoint(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.midpoint(Float::NEG_INFINITY).is_nan()); assert!(Float::NAN.midpoint(1.0).is_nan()); assert!((1.0 as Float).midpoint(Float::NAN).is_nan()); assert!(Float::NAN.midpoint(Float::NAN).is_nan()); From 25ec235b86f97a5b9f3d9ab1ab1bc72867c6bea4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Jun 2025 08:19:17 +0200 Subject: [PATCH 5/5] tweak runtime/const macro management --- library/coretests/tests/floats/mod.rs | 93 ++++++++++++++------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 8f15a2625af07..6b4f586fa9b6b 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -24,9 +24,11 @@ const fn lim_for_ty(_x: T) -> T { T::LIM } +// We have runtime ("rt") and const versions of these macros. + /// Verify that floats are within a tolerance of each other. -macro_rules! assert_approx_eq_ { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; +macro_rules! assert_approx_eq_rt { + ($a:expr, $b:expr) => {{ assert_approx_eq_rt!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); @@ -37,11 +39,18 @@ macro_rules! assert_approx_eq_ { ); }}; } -pub(crate) use assert_approx_eq_ as assert_approx_eq; +macro_rules! assert_approx_eq_const { + ($a:expr, $b:expr) => {{ assert_approx_eq_const!($a, $b, $crate::floats::lim_for_ty($a)) }}; + ($a:expr, $b:expr, $lim:expr) => {{ + let (a, b) = (&$a, &$b); + let diff = (*a - *b).abs(); + assert!(diff <= $lim); + }}; +} /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq_ { +macro_rules! assert_biteq_rt { (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ let l = $left; let r = $right; @@ -69,54 +78,45 @@ macro_rules! assert_biteq_ { } }}; ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq_!(@inner $left, $right, "\n", $($tt)*) + assert_biteq_rt!(@inner $left, $right, "\n", $($tt)*) }; ($left:expr, $right:expr $(,)?) => { - assert_biteq_!(@inner $left, $right, "", "") + assert_biteq_rt!(@inner $left, $right, "", "") }; } -pub(crate) use assert_biteq_ as assert_biteq; +macro_rules! assert_biteq_const { + (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ + let l = $left; + let r = $right; -mod const_asserts { - // Shadow some assert implementations that would otherwise not compile in a const-context. - // Every macro added here also needs to be added in the `float_test!` macro below. + // Hack to coerce left and right to the same type + let mut _eq_ty = l; + _eq_ty = r; - macro_rules! assert_biteq { - (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ - let l = $left; - let r = $right; + assert!(l.to_bits() == r.to_bits()); - // Hack to coerce left and right to the same type - let mut _eq_ty = l; - _eq_ty = r; + if !l.is_nan() && !r.is_nan() { + // Also check that standard equality holds, since most tests use `assert_biteq` rather + // than `assert_eq`. + assert!(l == r); + } + }}; + ($left:expr, $right:expr , $($tt:tt)*) => { + assert_biteq_const!(@inner $left, $right, "\n", $($tt)*) + }; + ($left:expr, $right:expr $(,)?) => { + assert_biteq_const!(@inner $left, $right, "", "") + }; +} - assert!(l.to_bits() == r.to_bits()); +// Use the runtime version by default. +// This way, they can be shadowed by the const versions. +pub(crate) use {assert_approx_eq_rt as assert_approx_eq, assert_biteq_rt as assert_biteq}; - if !l.is_nan() && !r.is_nan() { - // Also check that standard equality holds, since most tests use `assert_biteq` rather - // than `assert_eq`. - assert!(l == r); - } - }}; - ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq!(@inner $left, $right, "\n", $($tt)*) - }; - ($left:expr, $right:expr $(,)?) => { - assert_biteq!(@inner $left, $right, "", "") - }; - } - pub(crate) use assert_biteq; - - macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; - ($a:expr, $b:expr, $lim:expr) => {{ - let (a, b) = (&$a, &$b); - let diff = (*a - *b).abs(); - assert!(diff <= $lim); - }}; - } - pub(crate) use assert_approx_eq; -} +// Also make the const version available for re-exports. +#[rustfmt::skip] +pub(crate) use assert_biteq_const; +pub(crate) use assert_approx_eq_const; /// Generate float tests for all our float types, for compile-time and run-time behavior. /// @@ -135,6 +135,7 @@ mod const_asserts { /// /* write tests here, using `Float` as the type */ /// } /// } +/// ``` macro_rules! float_test { ( name: $name:ident, @@ -186,8 +187,12 @@ macro_rules! float_test { mod const_ { #[allow(unused)] use super::Approx; + // Shadow the runtime versions of the macro with const-compatible versions. #[allow(unused)] - use $crate::floats::const_asserts::{assert_biteq, assert_approx_eq}; + use $crate::floats::{ + assert_approx_eq_const as assert_approx_eq, + assert_biteq_const as assert_biteq, + }; #[test] $( $( #[$f16_const_meta] )+ )?