Skip to content

Commit 6e6adb4

Browse files
authored
Rollup merge of rust-lang#88728 - orlp:float-next-up-down, r=yaahc
Added next_up and next_down for f32/f64. This is a pull request implementing the features described at rust-lang/rfcs#3173.
2 parents f24b5da + 4dd9b85 commit 6e6adb4

File tree

5 files changed

+323
-0
lines changed

5 files changed

+323
-0
lines changed

library/core/src/num/f32.rs

+98
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,104 @@ impl f32 {
620620
self.to_bits() & 0x8000_0000 != 0
621621
}
622622

623+
/// Returns the least number greater than `self`.
624+
///
625+
/// Let `TINY` be the smallest representable positive `f32`. Then,
626+
/// - if `self.is_nan()`, this returns `self`;
627+
/// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
628+
/// - if `self` is `-TINY`, this returns -0.0;
629+
/// - if `self` is -0.0 or +0.0, this returns `TINY`;
630+
/// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
631+
/// - otherwise the unique least value greater than `self` is returned.
632+
///
633+
/// The identity `x.next_up() == -(-x).next_down()` holds for all `x`. When `x`
634+
/// is finite `x == x.next_up().next_down()` also holds.
635+
///
636+
/// ```rust
637+
/// #![feature(float_next_up_down)]
638+
/// // f32::EPSILON is the difference between 1.0 and the next number up.
639+
/// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
640+
/// // But not for most numbers.
641+
/// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON);
642+
/// assert_eq!(16777216f32.next_up(), 16777218.0);
643+
/// ```
644+
///
645+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
646+
/// [`INFINITY`]: Self::INFINITY
647+
/// [`MIN`]: Self::MIN
648+
/// [`MAX`]: Self::MAX
649+
#[unstable(feature = "float_next_up_down", issue = "none")]
650+
pub const fn next_up(self) -> Self {
651+
// We must use strictly integer arithmetic to prevent denormals from
652+
// flushing to zero after an arithmetic operation on some platforms.
653+
const TINY_BITS: u32 = 0x1; // Smallest positive f32.
654+
const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff;
655+
656+
let bits = self.to_bits();
657+
if self.is_nan() || bits == Self::INFINITY.to_bits() {
658+
return self;
659+
}
660+
661+
let abs = bits & CLEAR_SIGN_MASK;
662+
let next_bits = if abs == 0 {
663+
TINY_BITS
664+
} else if bits == abs {
665+
bits + 1
666+
} else {
667+
bits - 1
668+
};
669+
Self::from_bits(next_bits)
670+
}
671+
672+
/// Returns the greatest number less than `self`.
673+
///
674+
/// Let `TINY` be the smallest representable positive `f32`. Then,
675+
/// - if `self.is_nan()`, this returns `self`;
676+
/// - if `self` is [`INFINITY`], this returns [`MAX`];
677+
/// - if `self` is `TINY`, this returns 0.0;
678+
/// - if `self` is -0.0 or +0.0, this returns `-TINY`;
679+
/// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
680+
/// - otherwise the unique greatest value less than `self` is returned.
681+
///
682+
/// The identity `x.next_down() == -(-x).next_up()` holds for all `x`. When `x`
683+
/// is finite `x == x.next_down().next_up()` also holds.
684+
///
685+
/// ```rust
686+
/// #![feature(float_next_up_down)]
687+
/// let x = 1.0f32;
688+
/// // Clamp value into range [0, 1).
689+
/// let clamped = x.clamp(0.0, 1.0f32.next_down());
690+
/// assert!(clamped < 1.0);
691+
/// assert_eq!(clamped.next_up(), 1.0);
692+
/// ```
693+
///
694+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
695+
/// [`INFINITY`]: Self::INFINITY
696+
/// [`MIN`]: Self::MIN
697+
/// [`MAX`]: Self::MAX
698+
#[unstable(feature = "float_next_up_down", issue = "none")]
699+
pub const fn next_down(self) -> Self {
700+
// We must use strictly integer arithmetic to prevent denormals from
701+
// flushing to zero after an arithmetic operation on some platforms.
702+
const NEG_TINY_BITS: u32 = 0x8000_0001; // Smallest (in magnitude) negative f32.
703+
const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff;
704+
705+
let bits = self.to_bits();
706+
if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
707+
return self;
708+
}
709+
710+
let abs = bits & CLEAR_SIGN_MASK;
711+
let next_bits = if abs == 0 {
712+
NEG_TINY_BITS
713+
} else if bits == abs {
714+
bits - 1
715+
} else {
716+
bits + 1
717+
};
718+
Self::from_bits(next_bits)
719+
}
720+
623721
/// Takes the reciprocal (inverse) of a number, `1/x`.
624722
///
625723
/// ```

library/core/src/num/f64.rs

+98
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,104 @@ impl f64 {
635635
self.is_sign_negative()
636636
}
637637

638+
/// Returns the least number greater than `self`.
639+
///
640+
/// Let `TINY` be the smallest representable positive `f64`. Then,
641+
/// - if `self.is_nan()`, this returns `self`;
642+
/// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
643+
/// - if `self` is `-TINY`, this returns -0.0;
644+
/// - if `self` is -0.0 or +0.0, this returns `TINY`;
645+
/// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
646+
/// - otherwise the unique least value greater than `self` is returned.
647+
///
648+
/// The identity `x.next_up() == -(-x).next_down()` holds for all `x`. When `x`
649+
/// is finite `x == x.next_up().next_down()` also holds.
650+
///
651+
/// ```rust
652+
/// #![feature(float_next_up_down)]
653+
/// // f64::EPSILON is the difference between 1.0 and the next number up.
654+
/// assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
655+
/// // But not for most numbers.
656+
/// assert!(0.1f64.next_up() < 0.1 + f64::EPSILON);
657+
/// assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0);
658+
/// ```
659+
///
660+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
661+
/// [`INFINITY`]: Self::INFINITY
662+
/// [`MIN`]: Self::MIN
663+
/// [`MAX`]: Self::MAX
664+
#[unstable(feature = "float_next_up_down", issue = "none")]
665+
pub const fn next_up(self) -> Self {
666+
// We must use strictly integer arithmetic to prevent denormals from
667+
// flushing to zero after an arithmetic operation on some platforms.
668+
const TINY_BITS: u64 = 0x1; // Smallest positive f64.
669+
const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;
670+
671+
let bits = self.to_bits();
672+
if self.is_nan() || bits == Self::INFINITY.to_bits() {
673+
return self;
674+
}
675+
676+
let abs = bits & CLEAR_SIGN_MASK;
677+
let next_bits = if abs == 0 {
678+
TINY_BITS
679+
} else if bits == abs {
680+
bits + 1
681+
} else {
682+
bits - 1
683+
};
684+
Self::from_bits(next_bits)
685+
}
686+
687+
/// Returns the greatest number less than `self`.
688+
///
689+
/// Let `TINY` be the smallest representable positive `f64`. Then,
690+
/// - if `self.is_nan()`, this returns `self`;
691+
/// - if `self` is [`INFINITY`], this returns [`MAX`];
692+
/// - if `self` is `TINY`, this returns 0.0;
693+
/// - if `self` is -0.0 or +0.0, this returns `-TINY`;
694+
/// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
695+
/// - otherwise the unique greatest value less than `self` is returned.
696+
///
697+
/// The identity `x.next_down() == -(-x).next_up()` holds for all `x`. When `x`
698+
/// is finite `x == x.next_down().next_up()` also holds.
699+
///
700+
/// ```rust
701+
/// #![feature(float_next_up_down)]
702+
/// let x = 1.0f64;
703+
/// // Clamp value into range [0, 1).
704+
/// let clamped = x.clamp(0.0, 1.0f64.next_down());
705+
/// assert!(clamped < 1.0);
706+
/// assert_eq!(clamped.next_up(), 1.0);
707+
/// ```
708+
///
709+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
710+
/// [`INFINITY`]: Self::INFINITY
711+
/// [`MIN`]: Self::MIN
712+
/// [`MAX`]: Self::MAX
713+
#[unstable(feature = "float_next_up_down", issue = "none")]
714+
pub const fn next_down(self) -> Self {
715+
// We must use strictly integer arithmetic to prevent denormals from
716+
// flushing to zero after an arithmetic operation on some platforms.
717+
const NEG_TINY_BITS: u64 = 0x8000_0000_0000_0001; // Smallest (in magnitude) negative f64.
718+
const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;
719+
720+
let bits = self.to_bits();
721+
if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
722+
return self;
723+
}
724+
725+
let abs = bits & CLEAR_SIGN_MASK;
726+
let next_bits = if abs == 0 {
727+
NEG_TINY_BITS
728+
} else if bits == abs {
729+
bits - 1
730+
} else {
731+
bits + 1
732+
};
733+
Self::from_bits(next_bits)
734+
}
735+
638736
/// Takes the reciprocal (inverse) of a number, `1/x`.
639737
///
640738
/// ```

library/std/src/f32/tests.rs

+63
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,69 @@ fn test_is_sign_negative() {
287287
assert!((-f32::NAN).is_sign_negative());
288288
}
289289

290+
#[test]
291+
fn test_next_up() {
292+
let tiny = f32::from_bits(1);
293+
let tiny_up = f32::from_bits(2);
294+
let max_down = f32::from_bits(0x7f7f_fffe);
295+
let largest_subnormal = f32::from_bits(0x007f_ffff);
296+
let smallest_normal = f32::from_bits(0x0080_0000);
297+
298+
// Check that NaNs roundtrip.
299+
let nan0 = f32::NAN.to_bits();
300+
let nan1 = f32::NAN.to_bits() ^ 0x002a_aaaa;
301+
let nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
302+
assert_eq!(f32::from_bits(nan0).next_up().to_bits(), nan0);
303+
assert_eq!(f32::from_bits(nan1).next_up().to_bits(), nan1);
304+
assert_eq!(f32::from_bits(nan2).next_up().to_bits(), nan2);
305+
306+
assert_eq!(f32::NEG_INFINITY.next_up(), f32::MIN);
307+
assert_eq!(f32::MIN.next_up(), -max_down);
308+
assert_eq!((-1.0 - f32::EPSILON).next_up(), -1.0);
309+
assert_eq!((-smallest_normal).next_up(), -largest_subnormal);
310+
assert_eq!((-tiny_up).next_up(), -tiny);
311+
assert_eq!((-tiny).next_up().to_bits(), (-0.0f32).to_bits());
312+
assert_eq!((-0.0f32).next_up(), tiny);
313+
assert_eq!(0.0f32.next_up(), tiny);
314+
assert_eq!(tiny.next_up(), tiny_up);
315+
assert_eq!(largest_subnormal.next_up(), smallest_normal);
316+
assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
317+
assert_eq!(f32::MAX.next_up(), f32::INFINITY);
318+
assert_eq!(f32::INFINITY.next_up(), f32::INFINITY);
319+
}
320+
321+
#[test]
322+
fn test_next_down() {
323+
let tiny = f32::from_bits(1);
324+
let tiny_up = f32::from_bits(2);
325+
let max_down = f32::from_bits(0x7f7f_fffe);
326+
let largest_subnormal = f32::from_bits(0x007f_ffff);
327+
let smallest_normal = f32::from_bits(0x0080_0000);
328+
329+
// Check that NaNs roundtrip.
330+
let nan0 = f32::NAN.to_bits();
331+
let nan1 = f32::NAN.to_bits() ^ 0x002a_aaaa;
332+
let nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
333+
assert_eq!(f32::from_bits(nan0).next_down().to_bits(), nan0);
334+
assert_eq!(f32::from_bits(nan1).next_down().to_bits(), nan1);
335+
assert_eq!(f32::from_bits(nan2).next_down().to_bits(), nan2);
336+
337+
assert_eq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY);
338+
assert_eq!(f32::MIN.next_down(), f32::NEG_INFINITY);
339+
assert_eq!((-max_down).next_down(), f32::MIN);
340+
assert_eq!((-1.0f32).next_down(), -1.0 - f32::EPSILON);
341+
assert_eq!((-largest_subnormal).next_down(), -smallest_normal);
342+
assert_eq!((-tiny).next_down(), -tiny_up);
343+
assert_eq!((-0.0f32).next_down(), -tiny);
344+
assert_eq!((0.0f32).next_down(), -tiny);
345+
assert_eq!(tiny.next_down().to_bits(), 0.0f32.to_bits());
346+
assert_eq!(tiny_up.next_down(), tiny);
347+
assert_eq!(smallest_normal.next_down(), largest_subnormal);
348+
assert_eq!((1.0 + f32::EPSILON).next_down(), 1.0f32);
349+
assert_eq!(f32::MAX.next_down(), max_down);
350+
assert_eq!(f32::INFINITY.next_down(), f32::MAX);
351+
}
352+
290353
#[test]
291354
fn test_mul_add() {
292355
let nan: f32 = f32::NAN;

library/std/src/f64/tests.rs

+63
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,69 @@ fn test_is_sign_negative() {
289289
assert!((-f64::NAN).is_sign_negative());
290290
}
291291

292+
#[test]
293+
fn test_next_up() {
294+
let tiny = f64::from_bits(1);
295+
let tiny_up = f64::from_bits(2);
296+
let max_down = f64::from_bits(0x7fef_ffff_ffff_fffe);
297+
let largest_subnormal = f64::from_bits(0x000f_ffff_ffff_ffff);
298+
let smallest_normal = f64::from_bits(0x0010_0000_0000_0000);
299+
300+
// Check that NaNs roundtrip.
301+
let nan0 = f64::NAN.to_bits();
302+
let nan1 = f64::NAN.to_bits() ^ 0x000a_aaaa_aaaa_aaaa;
303+
let nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
304+
assert_eq!(f64::from_bits(nan0).next_up().to_bits(), nan0);
305+
assert_eq!(f64::from_bits(nan1).next_up().to_bits(), nan1);
306+
assert_eq!(f64::from_bits(nan2).next_up().to_bits(), nan2);
307+
308+
assert_eq!(f64::NEG_INFINITY.next_up(), f64::MIN);
309+
assert_eq!(f64::MIN.next_up(), -max_down);
310+
assert_eq!((-1.0 - f64::EPSILON).next_up(), -1.0);
311+
assert_eq!((-smallest_normal).next_up(), -largest_subnormal);
312+
assert_eq!((-tiny_up).next_up(), -tiny);
313+
assert_eq!((-tiny).next_up().to_bits(), (-0.0f64).to_bits());
314+
assert_eq!((-0.0f64).next_up(), tiny);
315+
assert_eq!(0.0f64.next_up(), tiny);
316+
assert_eq!(tiny.next_up(), tiny_up);
317+
assert_eq!(largest_subnormal.next_up(), smallest_normal);
318+
assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
319+
assert_eq!(f64::MAX.next_up(), f64::INFINITY);
320+
assert_eq!(f64::INFINITY.next_up(), f64::INFINITY);
321+
}
322+
323+
#[test]
324+
fn test_next_down() {
325+
let tiny = f64::from_bits(1);
326+
let tiny_up = f64::from_bits(2);
327+
let max_down = f64::from_bits(0x7fef_ffff_ffff_fffe);
328+
let largest_subnormal = f64::from_bits(0x000f_ffff_ffff_ffff);
329+
let smallest_normal = f64::from_bits(0x0010_0000_0000_0000);
330+
331+
// Check that NaNs roundtrip.
332+
let nan0 = f64::NAN.to_bits();
333+
let nan1 = f64::NAN.to_bits() ^ 0x000a_aaaa_aaaa_aaaa;
334+
let nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
335+
assert_eq!(f64::from_bits(nan0).next_down().to_bits(), nan0);
336+
assert_eq!(f64::from_bits(nan1).next_down().to_bits(), nan1);
337+
assert_eq!(f64::from_bits(nan2).next_down().to_bits(), nan2);
338+
339+
assert_eq!(f64::NEG_INFINITY.next_down(), f64::NEG_INFINITY);
340+
assert_eq!(f64::MIN.next_down(), f64::NEG_INFINITY);
341+
assert_eq!((-max_down).next_down(), f64::MIN);
342+
assert_eq!((-1.0f64).next_down(), -1.0 - f64::EPSILON);
343+
assert_eq!((-largest_subnormal).next_down(), -smallest_normal);
344+
assert_eq!((-tiny).next_down(), -tiny_up);
345+
assert_eq!((-0.0f64).next_down(), -tiny);
346+
assert_eq!((0.0f64).next_down(), -tiny);
347+
assert_eq!(tiny.next_down().to_bits(), 0.0f64.to_bits());
348+
assert_eq!(tiny_up.next_down(), tiny);
349+
assert_eq!(smallest_normal.next_down(), largest_subnormal);
350+
assert_eq!((1.0 + f64::EPSILON).next_down(), 1.0f64);
351+
assert_eq!(f64::MAX.next_down(), max_down);
352+
assert_eq!(f64::INFINITY.next_down(), f64::MAX);
353+
}
354+
292355
#[test]
293356
fn test_mul_add() {
294357
let nan: f64 = f64::NAN;

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@
285285
#![feature(exhaustive_patterns)]
286286
#![feature(extend_one)]
287287
#![feature(float_interpolation)]
288+
#![feature(float_next_up_down)]
288289
#![feature(fn_traits)]
289290
#![feature(format_args_nl)]
290291
#![feature(gen_future)]

0 commit comments

Comments
 (0)