Skip to content

Commit 0468189

Browse files
orlpUrgau
authored andcommitted
Added next_up and next_down for f32/f64.
1 parent 6ce7609 commit 0468189

File tree

5 files changed

+323
-0
lines changed

5 files changed

+323
-0
lines changed

library/core/src/num/f32.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,104 @@ impl f32 {
678678
unsafe { mem::transmute::<f32, u32>(self) & 0x8000_0000 != 0 }
679679
}
680680

681+
/// Returns the least number greater than `self`.
682+
///
683+
/// Let `TINY` be the smallest representable positive `f32`. Then,
684+
/// - if `self.is_nan()`, this returns `self`;
685+
/// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
686+
/// - if `self` is `-TINY`, this returns -0.0;
687+
/// - if `self` is -0.0 or +0.0, this returns `TINY`;
688+
/// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
689+
/// - otherwise the unique least value greater than `self` is returned.
690+
///
691+
/// The identity `x.next_up() == -(-x).next_down()` holds for all `x`. When `x`
692+
/// is finite `x == x.next_up().next_down()` also holds.
693+
///
694+
/// ```rust
695+
/// #![feature(float_next_up_down)]
696+
/// // f32::EPSILON is the difference between 1.0 and the next number up.
697+
/// assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
698+
/// // But not for most numbers.
699+
/// assert!(0.1f32.next_up() < 0.1 + f32::EPSILON);
700+
/// assert_eq!(16777216f32.next_up(), 16777218.0);
701+
/// ```
702+
///
703+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
704+
/// [`INFINITY`]: Self::INFINITY
705+
/// [`MIN`]: Self::MIN
706+
/// [`MAX`]: Self::MAX
707+
#[unstable(feature = "float_next_up_down", issue = "none")]
708+
pub const fn next_up(self) -> Self {
709+
// We must use strictly integer arithmetic to prevent denormals from
710+
// flushing to zero after an arithmetic operation on some platforms.
711+
const TINY_BITS: u32 = 0x1; // Smallest positive f32.
712+
const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff;
713+
714+
let bits = self.to_bits();
715+
if self.is_nan() || bits == Self::INFINITY.to_bits() {
716+
return self;
717+
}
718+
719+
let abs = bits & CLEAR_SIGN_MASK;
720+
let next_bits = if abs == 0 {
721+
TINY_BITS
722+
} else if bits == abs {
723+
bits + 1
724+
} else {
725+
bits - 1
726+
};
727+
Self::from_bits(next_bits)
728+
}
729+
730+
/// Returns the greatest number less than `self`.
731+
///
732+
/// Let `TINY` be the smallest representable positive `f32`. Then,
733+
/// - if `self.is_nan()`, this returns `self`;
734+
/// - if `self` is [`INFINITY`], this returns [`MAX`];
735+
/// - if `self` is `TINY`, this returns 0.0;
736+
/// - if `self` is -0.0 or +0.0, this returns `-TINY`;
737+
/// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
738+
/// - otherwise the unique greatest value less than `self` is returned.
739+
///
740+
/// The identity `x.next_down() == -(-x).next_up()` holds for all `x`. When `x`
741+
/// is finite `x == x.next_down().next_up()` also holds.
742+
///
743+
/// ```rust
744+
/// #![feature(float_next_up_down)]
745+
/// let x = 1.0f32;
746+
/// // Clamp value into range [0, 1).
747+
/// let clamped = x.clamp(0.0, 1.0f32.next_down());
748+
/// assert!(clamped < 1.0);
749+
/// assert_eq!(clamped.next_up(), 1.0);
750+
/// ```
751+
///
752+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
753+
/// [`INFINITY`]: Self::INFINITY
754+
/// [`MIN`]: Self::MIN
755+
/// [`MAX`]: Self::MAX
756+
#[unstable(feature = "float_next_up_down", issue = "none")]
757+
pub const fn next_down(self) -> Self {
758+
// We must use strictly integer arithmetic to prevent denormals from
759+
// flushing to zero after an arithmetic operation on some platforms.
760+
const NEG_TINY_BITS: u32 = 0x8000_0001; // Smallest (in magnitude) negative f32.
761+
const CLEAR_SIGN_MASK: u32 = 0x7fff_ffff;
762+
763+
let bits = self.to_bits();
764+
if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
765+
return self;
766+
}
767+
768+
let abs = bits & CLEAR_SIGN_MASK;
769+
let next_bits = if abs == 0 {
770+
NEG_TINY_BITS
771+
} else if bits == abs {
772+
bits - 1
773+
} else {
774+
bits + 1
775+
};
776+
Self::from_bits(next_bits)
777+
}
778+
681779
/// Takes the reciprocal (inverse) of a number, `1/x`.
682780
///
683781
/// ```

library/core/src/num/f64.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,104 @@ impl f64 {
688688
self.is_sign_negative()
689689
}
690690

691+
/// Returns the least number greater than `self`.
692+
///
693+
/// Let `TINY` be the smallest representable positive `f64`. Then,
694+
/// - if `self.is_nan()`, this returns `self`;
695+
/// - if `self` is [`NEG_INFINITY`], this returns [`MIN`];
696+
/// - if `self` is `-TINY`, this returns -0.0;
697+
/// - if `self` is -0.0 or +0.0, this returns `TINY`;
698+
/// - if `self` is [`MAX`] or [`INFINITY`], this returns [`INFINITY`];
699+
/// - otherwise the unique least value greater than `self` is returned.
700+
///
701+
/// The identity `x.next_up() == -(-x).next_down()` holds for all `x`. When `x`
702+
/// is finite `x == x.next_up().next_down()` also holds.
703+
///
704+
/// ```rust
705+
/// #![feature(float_next_up_down)]
706+
/// // f64::EPSILON is the difference between 1.0 and the next number up.
707+
/// assert_eq!(1.0f64.next_up(), 1.0 + f64::EPSILON);
708+
/// // But not for most numbers.
709+
/// assert!(0.1f64.next_up() < 0.1 + f64::EPSILON);
710+
/// assert_eq!(9007199254740992f64.next_up(), 9007199254740994.0);
711+
/// ```
712+
///
713+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
714+
/// [`INFINITY`]: Self::INFINITY
715+
/// [`MIN`]: Self::MIN
716+
/// [`MAX`]: Self::MAX
717+
#[unstable(feature = "float_next_up_down", issue = "none")]
718+
pub const fn next_up(self) -> Self {
719+
// We must use strictly integer arithmetic to prevent denormals from
720+
// flushing to zero after an arithmetic operation on some platforms.
721+
const TINY_BITS: u64 = 0x1; // Smallest positive f64.
722+
const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;
723+
724+
let bits = self.to_bits();
725+
if self.is_nan() || bits == Self::INFINITY.to_bits() {
726+
return self;
727+
}
728+
729+
let abs = bits & CLEAR_SIGN_MASK;
730+
let next_bits = if abs == 0 {
731+
TINY_BITS
732+
} else if bits == abs {
733+
bits + 1
734+
} else {
735+
bits - 1
736+
};
737+
Self::from_bits(next_bits)
738+
}
739+
740+
/// Returns the greatest number less than `self`.
741+
///
742+
/// Let `TINY` be the smallest representable positive `f64`. Then,
743+
/// - if `self.is_nan()`, this returns `self`;
744+
/// - if `self` is [`INFINITY`], this returns [`MAX`];
745+
/// - if `self` is `TINY`, this returns 0.0;
746+
/// - if `self` is -0.0 or +0.0, this returns `-TINY`;
747+
/// - if `self` is [`MIN`] or [`NEG_INFINITY`], this returns [`NEG_INFINITY`];
748+
/// - otherwise the unique greatest value less than `self` is returned.
749+
///
750+
/// The identity `x.next_down() == -(-x).next_up()` holds for all `x`. When `x`
751+
/// is finite `x == x.next_down().next_up()` also holds.
752+
///
753+
/// ```rust
754+
/// #![feature(float_next_up_down)]
755+
/// let x = 1.0f64;
756+
/// // Clamp value into range [0, 1).
757+
/// let clamped = x.clamp(0.0, 1.0f64.next_down());
758+
/// assert!(clamped < 1.0);
759+
/// assert_eq!(clamped.next_up(), 1.0);
760+
/// ```
761+
///
762+
/// [`NEG_INFINITY`]: Self::NEG_INFINITY
763+
/// [`INFINITY`]: Self::INFINITY
764+
/// [`MIN`]: Self::MIN
765+
/// [`MAX`]: Self::MAX
766+
#[unstable(feature = "float_next_up_down", issue = "none")]
767+
pub const fn next_down(self) -> Self {
768+
// We must use strictly integer arithmetic to prevent denormals from
769+
// flushing to zero after an arithmetic operation on some platforms.
770+
const NEG_TINY_BITS: u64 = 0x8000_0000_0000_0001; // Smallest (in magnitude) negative f64.
771+
const CLEAR_SIGN_MASK: u64 = 0x7fff_ffff_ffff_ffff;
772+
773+
let bits = self.to_bits();
774+
if self.is_nan() || bits == Self::NEG_INFINITY.to_bits() {
775+
return self;
776+
}
777+
778+
let abs = bits & CLEAR_SIGN_MASK;
779+
let next_bits = if abs == 0 {
780+
NEG_TINY_BITS
781+
} else if bits == abs {
782+
bits - 1
783+
} else {
784+
bits + 1
785+
};
786+
Self::from_bits(next_bits)
787+
}
788+
691789
/// Takes the reciprocal (inverse) of a number, `1/x`.
692790
///
693791
/// ```

library/std/src/f32/tests.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,69 @@ fn test_is_sign_negative() {
299299
assert!((-f32::NAN).is_sign_negative());
300300
}
301301

302+
#[test]
303+
fn test_next_up() {
304+
let tiny = f32::from_bits(1);
305+
let tiny_up = f32::from_bits(2);
306+
let max_down = f32::from_bits(0x7f7f_fffe);
307+
let largest_subnormal = f32::from_bits(0x007f_ffff);
308+
let smallest_normal = f32::from_bits(0x0080_0000);
309+
310+
// Check that NaNs roundtrip.
311+
let nan0 = f32::NAN.to_bits();
312+
let nan1 = f32::NAN.to_bits() ^ 0x002a_aaaa;
313+
let nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
314+
assert_eq!(f32::from_bits(nan0).next_up().to_bits(), nan0);
315+
assert_eq!(f32::from_bits(nan1).next_up().to_bits(), nan1);
316+
assert_eq!(f32::from_bits(nan2).next_up().to_bits(), nan2);
317+
318+
assert_eq!(f32::NEG_INFINITY.next_up(), f32::MIN);
319+
assert_eq!(f32::MIN.next_up(), -max_down);
320+
assert_eq!((-1.0 - f32::EPSILON).next_up(), -1.0);
321+
assert_eq!((-smallest_normal).next_up(), -largest_subnormal);
322+
assert_eq!((-tiny_up).next_up(), -tiny);
323+
assert_eq!((-tiny).next_up().to_bits(), (-0.0f32).to_bits());
324+
assert_eq!((-0.0f32).next_up(), tiny);
325+
assert_eq!(0.0f32.next_up(), tiny);
326+
assert_eq!(tiny.next_up(), tiny_up);
327+
assert_eq!(largest_subnormal.next_up(), smallest_normal);
328+
assert_eq!(1.0f32.next_up(), 1.0 + f32::EPSILON);
329+
assert_eq!(f32::MAX.next_up(), f32::INFINITY);
330+
assert_eq!(f32::INFINITY.next_up(), f32::INFINITY);
331+
}
332+
333+
#[test]
334+
fn test_next_down() {
335+
let tiny = f32::from_bits(1);
336+
let tiny_up = f32::from_bits(2);
337+
let max_down = f32::from_bits(0x7f7f_fffe);
338+
let largest_subnormal = f32::from_bits(0x007f_ffff);
339+
let smallest_normal = f32::from_bits(0x0080_0000);
340+
341+
// Check that NaNs roundtrip.
342+
let nan0 = f32::NAN.to_bits();
343+
let nan1 = f32::NAN.to_bits() ^ 0x002a_aaaa;
344+
let nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
345+
assert_eq!(f32::from_bits(nan0).next_down().to_bits(), nan0);
346+
assert_eq!(f32::from_bits(nan1).next_down().to_bits(), nan1);
347+
assert_eq!(f32::from_bits(nan2).next_down().to_bits(), nan2);
348+
349+
assert_eq!(f32::NEG_INFINITY.next_down(), f32::NEG_INFINITY);
350+
assert_eq!(f32::MIN.next_down(), f32::NEG_INFINITY);
351+
assert_eq!((-max_down).next_down(), f32::MIN);
352+
assert_eq!((-1.0f32).next_down(), -1.0 - f32::EPSILON);
353+
assert_eq!((-largest_subnormal).next_down(), -smallest_normal);
354+
assert_eq!((-tiny).next_down(), -tiny_up);
355+
assert_eq!((-0.0f32).next_down(), -tiny);
356+
assert_eq!((0.0f32).next_down(), -tiny);
357+
assert_eq!(tiny.next_down().to_bits(), 0.0f32.to_bits());
358+
assert_eq!(tiny_up.next_down(), tiny);
359+
assert_eq!(smallest_normal.next_down(), largest_subnormal);
360+
assert_eq!((1.0 + f32::EPSILON).next_down(), 1.0f32);
361+
assert_eq!(f32::MAX.next_down(), max_down);
362+
assert_eq!(f32::INFINITY.next_down(), f32::MAX);
363+
}
364+
302365
#[test]
303366
fn test_mul_add() {
304367
let nan: f32 = f32::NAN;

library/std/src/f64/tests.rs

Lines changed: 63 additions & 0 deletions
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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@
273273
#![feature(exclusive_wrapper)]
274274
#![feature(extend_one)]
275275
#![feature(float_minimum_maximum)]
276+
#![feature(float_next_up_down)]
276277
#![feature(hasher_prefixfree_extras)]
277278
#![feature(hashmap_internals)]
278279
#![feature(int_error_internals)]

0 commit comments

Comments
 (0)