Skip to content

Commit 4dd9b85

Browse files
committed
Added next_up and next_down for f32/f64.
1 parent 385f8e2 commit 4dd9b85

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
@@ -613,6 +613,104 @@ impl f32 {
613613
self.to_bits() & 0x8000_0000 != 0
614614
}
615615

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

library/core/src/num/f64.rs

+98
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,104 @@ impl f64 {
626626
self.is_sign_negative()
627627
}
628628

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

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
@@ -274,6 +274,7 @@
274274
#![feature(exhaustive_patterns)]
275275
#![feature(extend_one)]
276276
#![feature(float_interpolation)]
277+
#![feature(float_next_up_down)]
277278
#![feature(fn_traits)]
278279
#![feature(format_args_nl)]
279280
#![feature(gen_future)]

0 commit comments

Comments
 (0)