Skip to content

Commit bf73234

Browse files
committed
Implement midpoint for all floating point f32 and f64
1 parent 1a72d7c commit bf73234

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

library/core/src/num/f32.rs

+36
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,42 @@ impl f32 {
940940
}
941941
}
942942

943+
/// Calculates the middle point of `self` and `rhs`.
944+
///
945+
/// This returns NaN when *either* argument is NaN or if a combination of
946+
/// +inf and -inf is provided as arguments.
947+
///
948+
/// # Examples
949+
///
950+
/// ```
951+
/// #![feature(num_midpoint)]
952+
/// assert_eq!(1f32.midpoint(4.0), 2.5);
953+
/// assert_eq!((-5.5f32).midpoint(8.0), 1.25);
954+
/// ```
955+
#[unstable(feature = "num_midpoint", issue = "110840")]
956+
pub fn midpoint(self, other: f32) -> f32 {
957+
const LO: f32 = f32::MIN_POSITIVE * 2.;
958+
const HI: f32 = f32::MAX / 2.;
959+
960+
let (a, b) = (self, other);
961+
let abs_a = a.abs_private();
962+
let abs_b = b.abs_private();
963+
964+
if abs_a <= HI && abs_b <= HI {
965+
// Overflow is impossible
966+
(a + b) / 2.
967+
} else if abs_a < LO {
968+
// Not safe to halve a
969+
a + (b / 2.)
970+
} else if abs_b < LO {
971+
// Not safe to halve b
972+
(a / 2.) + b
973+
} else {
974+
// Not safe to halve a and b
975+
(a / 2.) + (b / 2.)
976+
}
977+
}
978+
943979
/// Rounds toward zero and converts to any primitive integer type,
944980
/// assuming that the value is finite and fits in that type.
945981
///

library/core/src/num/f64.rs

+36
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,42 @@ impl f64 {
951951
}
952952
}
953953

954+
/// Calculates the middle point of `self` and `rhs`.
955+
///
956+
/// This returns NaN when *either* argument is NaN or if a combination of
957+
/// +inf and -inf is provided as arguments.
958+
///
959+
/// # Examples
960+
///
961+
/// ```
962+
/// #![feature(num_midpoint)]
963+
/// assert_eq!(1f64.midpoint(4.0), 2.5);
964+
/// assert_eq!((-5.5f64).midpoint(8.0), 1.25);
965+
/// ```
966+
#[unstable(feature = "num_midpoint", issue = "110840")]
967+
pub fn midpoint(self, other: f64) -> f64 {
968+
const LO: f64 = f64::MIN_POSITIVE * 2.;
969+
const HI: f64 = f64::MAX / 2.;
970+
971+
let (a, b) = (self, other);
972+
let abs_a = a.abs_private();
973+
let abs_b = b.abs_private();
974+
975+
if abs_a <= HI && abs_b <= HI {
976+
// Overflow is impossible
977+
(a + b) / 2.
978+
} else if abs_a < LO {
979+
// Not safe to halve a
980+
a + (b / 2.)
981+
} else if abs_b < LO {
982+
// Not safe to halve b
983+
(a / 2.) + b
984+
} else {
985+
// Not safe to halve a and b
986+
(a / 2.) + (b / 2.)
987+
}
988+
}
989+
954990
/// Rounds toward zero and converts to any primitive integer type,
955991
/// assuming that the value is finite and fits in that type.
956992
///

library/core/tests/num/mod.rs

+53-3
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ assume_usize_width! {
724724
}
725725

726726
macro_rules! test_float {
727-
($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => {
727+
($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr) => {
728728
mod $modname {
729729
#[test]
730730
fn min() {
@@ -845,6 +845,38 @@ macro_rules! test_float {
845845
assert!(($nan as $fty).maximum($nan).is_nan());
846846
}
847847
#[test]
848+
fn midpoint() {
849+
assert_eq!((0.5 as $fty).midpoint(0.5), 0.5);
850+
assert_eq!((0.5 as $fty).midpoint(2.5), 1.5);
851+
assert_eq!((3.0 as $fty).midpoint(4.0), 3.5);
852+
assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5);
853+
assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5);
854+
assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5);
855+
assert_eq!((0.0 as $fty).midpoint(0.0), 0.0);
856+
assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0);
857+
assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0);
858+
assert_eq!(($max as $fty).midpoint($min), 0.0);
859+
assert_eq!(($min as $fty).midpoint($max), -0.0);
860+
assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.);
861+
assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.);
862+
assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.);
863+
assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.);
864+
assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.);
865+
assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.);
866+
assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.);
867+
assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.);
868+
assert_eq!(($max as $fty).midpoint($max), $max);
869+
assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos);
870+
assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos);
871+
assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5);
872+
assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5);
873+
assert_eq!(($inf as $fty).midpoint($inf), $inf);
874+
assert_eq!(($neginf as $fty).midpoint($neginf), $neginf);
875+
assert!(($nan as $fty).midpoint(1.0).is_nan());
876+
assert!((1.0 as $fty).midpoint($nan).is_nan());
877+
assert!(($nan as $fty).midpoint($nan).is_nan());
878+
}
879+
#[test]
848880
fn rem_euclid() {
849881
let a: $fty = 42.0;
850882
assert!($inf.rem_euclid(a).is_nan());
@@ -867,5 +899,23 @@ macro_rules! test_float {
867899
};
868900
}
869901

870-
test_float!(f32, f32, f32::INFINITY, f32::NEG_INFINITY, f32::NAN);
871-
test_float!(f64, f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN);
902+
test_float!(
903+
f32,
904+
f32,
905+
f32::INFINITY,
906+
f32::NEG_INFINITY,
907+
f32::NAN,
908+
f32::MIN,
909+
f32::MAX,
910+
f32::MIN_POSITIVE
911+
);
912+
test_float!(
913+
f64,
914+
f64,
915+
f64::INFINITY,
916+
f64::NEG_INFINITY,
917+
f64::NAN,
918+
f64::MIN,
919+
f64::MAX,
920+
f64::MIN_POSITIVE
921+
);

0 commit comments

Comments
 (0)