Rollup merge of #121062 - RustyYato:f32-midpoint, r=the8472 · model-checking/verify-rust-std@380d9a3
@@ -729,7 +729,7 @@ assume_usize_width! {
729729}
730730731731macro_rules! test_float {
732-($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr) => {
732+($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr, $max_exp:expr) => {
733733mod $modname {
734734 #[test]
735735fn min() {
@@ -880,6 +880,27 @@ macro_rules! test_float {
880880 assert!(($nan as $fty).midpoint(1.0).is_nan());
881881 assert!((1.0 as $fty).midpoint($nan).is_nan());
882882 assert!(($nan as $fty).midpoint($nan).is_nan());
883+884+// test if large differences in magnitude are still correctly computed.
885+// NOTE: that because of how small x and y are, x + y can never overflow
886+// so (x + y) / 2.0 is always correct
887+// in particular, `2.pow(i)` will never be at the max exponent, so it could
888+// be safely doubled, while j is significantly smaller.
889+for i in $max_exp.saturating_sub(64)..$max_exp {
890+for j in 0..64u8 {
891+let large = <$fty>::from(2.0f32).powi(i);
892+// a much smaller number, such that there is no chance of overflow to test
893+// potential double rounding in midpoint's implementation.
894+let small = <$fty>::from(2.0f32).powi($max_exp - 1)
895+* <$fty>::EPSILON
896+* <$fty>::from(j);
897+898+let naive = (large + small) / 2.0;
899+let midpoint = large.midpoint(small);
900+901+ assert_eq!(naive, midpoint);
902+}
903+}
883904}
884905 #[test]
885906fn rem_euclid() {
@@ -912,7 +933,8 @@ test_float!(
912933f32::NAN,
913934f32::MIN,
914935f32::MAX,
915-f32::MIN_POSITIVE
936+f32::MIN_POSITIVE,
937+f32::MAX_EXP
916938);
917939test_float!(
918940f64,
@@ -922,5 +944,6 @@ test_float!(
922944f64::NAN,
923945f64::MIN,
924946f64::MAX,
925-f64::MIN_POSITIVE
947+f64::MIN_POSITIVE,
948+f64::MAX_EXP
926949);