Auto merge of #127020 - tgross35:f16-f128-classify, r=workingjubilee · model-checking/verify-rust-std@ac443f2 (original) (raw)
`@@ -12,7 +12,10 @@
`
12
12
`#![unstable(feature = "f128", issue = "116909")]
`
13
13
``
14
14
`use crate::convert::FloatToInt;
`
``
15
`+
#[cfg(not(test))]
`
``
16
`+
use crate::intrinsics;
`
15
17
`use crate::mem;
`
``
18
`+
use crate::num::FpCategory;
`
16
19
``
17
20
`/// Basic mathematical constants.
`
18
21
`#[unstable(feature = "f128", issue = "116909")]
`
`@@ -251,6 +254,12 @@ impl f128 {
`
251
254
`#[cfg(not(bootstrap))]
`
252
255
`pub(crate) const SIGN_MASK: u128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
`
253
256
``
``
257
`+
/// Exponent mask
`
``
258
`+
pub(crate) const EXP_MASK: u128 = 0x7fff_0000_0000_0000_0000_0000_0000_0000;
`
``
259
+
``
260
`+
/// Mantissa mask
`
``
261
`+
pub(crate) const MAN_MASK: u128 = 0x0000_ffff_ffff_ffff_ffff_ffff_ffff_ffff;
`
``
262
+
254
263
`/// Minimum representable positive value (min subnormal)
`
255
264
`#[cfg(not(bootstrap))]
`
256
265
`const TINY_BITS: u128 = 0x1;
`
`@@ -354,6 +363,119 @@ impl f128 {
`
354
363
`self.abs_private() < Self::INFINITY
`
355
364
`}
`
356
365
``
``
366
`` +
/// Returns true
if the number is [subnormal].
``
``
367
`+
///
`
``
368
/// ```
``
369
`+
/// #![feature(f128)]
`
``
370
`` +
/// # // FIXME(f16_f128): remove when eqtf2
is available
``
``
371
`+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
`
``
372
`+
///
`
``
373
`+
/// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128
`
``
374
`+
/// let max = f128::MAX;
`
``
375
`+
/// let lower_than_min = 1.0e-4960_f128;
`
``
376
`+
/// let zero = 0.0_f128;
`
``
377
`+
///
`
``
378
`+
/// assert!(!min.is_subnormal());
`
``
379
`+
/// assert!(!max.is_subnormal());
`
``
380
`+
///
`
``
381
`+
/// assert!(!zero.is_subnormal());
`
``
382
`+
/// assert!(!f128::NAN.is_subnormal());
`
``
383
`+
/// assert!(!f128::INFINITY.is_subnormal());
`
``
384
`` +
/// // Values between 0
and min
are Subnormal.
``
``
385
`+
/// assert!(lower_than_min.is_subnormal());
`
``
386
`+
/// # }
`
``
387
/// ```
``
388
`+
///
`
``
389
`+
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
`
``
390
`+
#[inline]
`
``
391
`+
#[must_use]
`
``
392
`+
#[cfg(not(bootstrap))]
`
``
393
`+
#[unstable(feature = "f128", issue = "116909")]
`
``
394
`+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
`
``
395
`+
pub const fn is_subnormal(self) -> bool {
`
``
396
`+
matches!(self.classify(), FpCategory::Subnormal)
`
``
397
`+
}
`
``
398
+
``
399
`` +
/// Returns true
if the number is neither zero, infinite, [subnormal], or NaN.
``
``
400
`+
///
`
``
401
/// ```
``
402
`+
/// #![feature(f128)]
`
``
403
`` +
/// # // FIXME(f16_f128): remove when eqtf2
is available
``
``
404
`+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
`
``
405
`+
///
`
``
406
`+
/// let min = f128::MIN_POSITIVE; // 3.362103143e-4932f128
`
``
407
`+
/// let max = f128::MAX;
`
``
408
`+
/// let lower_than_min = 1.0e-4960_f128;
`
``
409
`+
/// let zero = 0.0_f128;
`
``
410
`+
///
`
``
411
`+
/// assert!(min.is_normal());
`
``
412
`+
/// assert!(max.is_normal());
`
``
413
`+
///
`
``
414
`+
/// assert!(!zero.is_normal());
`
``
415
`+
/// assert!(!f128::NAN.is_normal());
`
``
416
`+
/// assert!(!f128::INFINITY.is_normal());
`
``
417
`` +
/// // Values between 0
and min
are Subnormal.
``
``
418
`+
/// assert!(!lower_than_min.is_normal());
`
``
419
`+
/// # }
`
``
420
/// ```
``
421
`+
///
`
``
422
`+
/// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
`
``
423
`+
#[inline]
`
``
424
`+
#[must_use]
`
``
425
`+
#[cfg(not(bootstrap))]
`
``
426
`+
#[unstable(feature = "f128", issue = "116909")]
`
``
427
`+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
`
``
428
`+
pub const fn is_normal(self) -> bool {
`
``
429
`+
matches!(self.classify(), FpCategory::Normal)
`
``
430
`+
}
`
``
431
+
``
432
`+
/// Returns the floating point category of the number. If only one property
`
``
433
`+
/// is going to be tested, it is generally faster to use the specific
`
``
434
`+
/// predicate instead.
`
``
435
`+
///
`
``
436
/// ```
``
437
`+
/// #![feature(f128)]
`
``
438
`` +
/// # // FIXME(f16_f128): remove when eqtf2
is available
``
``
439
`+
/// # #[cfg(all(target_arch = "x86_64", target_os = "linux"))] {
`
``
440
`+
///
`
``
441
`+
/// use std::num::FpCategory;
`
``
442
`+
///
`
``
443
`+
/// let num = 12.4_f128;
`
``
444
`+
/// let inf = f128::INFINITY;
`
``
445
`+
///
`
``
446
`+
/// assert_eq!(num.classify(), FpCategory::Normal);
`
``
447
`+
/// assert_eq!(inf.classify(), FpCategory::Infinite);
`
``
448
`+
/// # }
`
``
449
/// ```
``
450
`+
#[inline]
`
``
451
`+
#[cfg(not(bootstrap))]
`
``
452
`+
#[unstable(feature = "f128", issue = "116909")]
`
``
453
`+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
`
``
454
`+
pub const fn classify(self) -> FpCategory {
`
``
455
`+
// Other float types cannot use a bitwise classify because they may suffer a variety
`
``
456
`` +
// of errors if the backend chooses to cast to different float types (x87). f128
cannot
``
``
457
`+
// fit into any other float types so this is not a concern, and we rely on bit patterns.
`
``
458
+
``
459
`` +
// SAFETY: POD bitcast, same as in to_bits
.
``
``
460
`+
let bits = unsafe { mem::transmute::<f128, u128>(self) };
`
``
461
`+
Self::classify_bits(bits)
`
``
462
`+
}
`
``
463
+
``
464
`+
/// This operates on bits, and only bits, so it can ignore concerns about weird FPUs.
`
``
465
`+
/// FIXME(jubilee): In a just world, this would be the entire impl for classify,
`
``
466
`+
/// plus a transmute. We do not live in a just world, but we can make it more so.
`
``
467
`+
#[inline]
`
``
468
`+
#[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
`
``
469
`+
const fn classify_bits(b: u128) -> FpCategory {
`
``
470
`+
match (b & Self::MAN_MASK, b & Self::EXP_MASK) {
`
``
471
`+
(0, Self::EXP_MASK) => FpCategory::Infinite,
`
``
472
`+
(_, Self::EXP_MASK) => FpCategory::Nan,
`
``
473
`+
(0, 0) => FpCategory::Zero,
`
``
474
`+
(_, 0) => FpCategory::Subnormal,
`
``
475
`+
_ => FpCategory::Normal,
`
``
476
`+
}
`
``
477
`+
}
`
``
478
+
357
479
`` /// Returns true
if self
has a positive sign, including +0.0
, NaNs with
``
358
480
`/// positive sign bit and positive infinity. Note that IEEE 754 doesn't assign any
`
359
481
`/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
`
`@@ -638,12 +760,52 @@ impl f128 {
`
638
760
```` /// ```
`639`
`761`
`#[inline]
`
`640`
`762`
`#[unstable(feature = "f128", issue = "116909")]
`
``
`763`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
`641`
`764`
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
`642`
``
`-
pub fn to_bits(self) -> u128 {
`
`643`
``
`` -
// SAFETY: `u128` is a plain old datatype so we can always... uh...
``
`644`
``
`-
// ...look, just pretend you forgot what you just read.
`
`645`
``
`-
// Stability concerns.
`
`646`
``
`-
unsafe { mem::transmute(self) }
`
``
`765`
`+
pub const fn to_bits(self) -> u128 {
`
``
`766`
`` +
// SAFETY: `u128` is a plain old datatype so we can always transmute to it.
``
``
`767`
`+
// ...sorta.
`
``
`768`
`+
//
`
``
`769`
`+
// It turns out that at runtime, it is possible for a floating point number
`
``
`770`
`+
// to be subject to a floating point mode that alters nonzero subnormal numbers
`
``
`771`
`+
// to zero on reads and writes, aka "denormals are zero" and "flush to zero".
`
``
`772`
`+
//
`
``
`773`
`+
// And, of course evaluating to a NaN value is fairly nondeterministic.
`
``
`774`
`+
// More precisely: when NaN should be returned is knowable, but which NaN?
`
``
`775`
`+
// So far that's defined by a combination of LLVM and the CPU, not Rust.
`
``
`776`
`+
// This function, however, allows observing the bitstring of a NaN,
`
``
`777`
`+
// thus introspection on CTFE.
`
``
`778`
`+
//
`
``
`779`
`+
// In order to preserve, at least for the moment, const-to-runtime equivalence,
`
``
`780`
`+
// we reject any of these possible situations from happening.
`
``
`781`
`+
#[inline]
`
``
`782`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
`783`
`+
const fn ct_f128_to_u128(ct: f128) -> u128 {
`
``
`784`
`` +
// FIXME(f16_f128): we should use `.classify()` like `f32` and `f64`, but that
``
``
`785`
`` +
// is not available on all platforms (needs `netf2` and `unordtf2`). So classify
``
``
`786`
`+
// the bits instead.
`
``
`787`
`+`
``
`788`
`+
// SAFETY: this is a POD transmutation
`
``
`789`
`+
let bits = unsafe { mem::transmute::<f128, u128>(ct) };
`
``
`790`
`+
match f128::classify_bits(bits) {
`
``
`791`
`+
FpCategory::Nan => {
`
``
`792`
`+
panic!("const-eval error: cannot use f128::to_bits on a NaN")
`
``
`793`
`+
}
`
``
`794`
`+
FpCategory::Subnormal => {
`
``
`795`
`+
panic!("const-eval error: cannot use f128::to_bits on a subnormal number")
`
``
`796`
`+
}
`
``
`797`
`+
FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => bits,
`
``
`798`
`+
}
`
``
`799`
`+
}
`
``
`800`
`+`
``
`801`
`+
#[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
`
``
`802`
`+
fn rt_f128_to_u128(x: f128) -> u128 {
`
``
`803`
`` +
// SAFETY: `u128` is a plain old datatype so we can always... uh...
``
``
`804`
`+
// ...look, just pretend you forgot what you just read.
`
``
`805`
`+
// Stability concerns.
`
``
`806`
`+
unsafe { mem::transmute(x) }
`
``
`807`
`+
}
`
``
`808`
`+
intrinsics::const_eval_select((self,), ct_f128_to_u128, rt_f128_to_u128)
`
`647`
`809`
`}
`
`648`
`810`
``
`649`
`811`
`` /// Raw transmutation from `u128`.
``
`@@ -688,11 +850,52 @@ impl f128 {
`
`688`
`850`
`#[inline]
`
`689`
`851`
`#[must_use]
`
`690`
`852`
`#[unstable(feature = "f128", issue = "116909")]
`
`691`
``
`-
pub fn from_bits(v: u128) -> Self {
`
`692`
``
`` -
// SAFETY: `u128 is a plain old datatype so we can always... uh...
``
`693`
``
`-
// ...look, just pretend you forgot what you just read.
`
`694`
``
`-
// Stability concerns.
`
`695`
``
`-
unsafe { mem::transmute(v) }
`
``
`853`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
`854`
`+
pub const fn from_bits(v: u128) -> Self {
`
``
`855`
`+
// It turns out the safety issues with sNaN were overblown! Hooray!
`
``
`856`
`` +
// SAFETY: `u128` is a plain old datatype so we can always transmute from it
``
``
`857`
`+
// ...sorta.
`
``
`858`
`+
//
`
``
`859`
`+
// It turns out that at runtime, it is possible for a floating point number
`
``
`860`
`+
// to be subject to floating point modes that alter nonzero subnormal numbers
`
``
`861`
`+
// to zero on reads and writes, aka "denormals are zero" and "flush to zero".
`
``
`862`
`+
// This is not a problem usually, but at least one tier2 platform for Rust
`
``
`863`
`+
// actually exhibits this behavior by default: thumbv7neon
`
``
`864`
`+
// aka "the Neon FPU in AArch32 state"
`
``
`865`
`+
//
`
``
`866`
`+
// And, of course evaluating to a NaN value is fairly nondeterministic.
`
``
`867`
`+
// More precisely: when NaN should be returned is knowable, but which NaN?
`
``
`868`
`+
// So far that's defined by a combination of LLVM and the CPU, not Rust.
`
``
`869`
`+
// This function, however, allows observing the bitstring of a NaN,
`
``
`870`
`+
// thus introspection on CTFE.
`
``
`871`
`+
//
`
``
`872`
`+
// In order to preserve, at least for the moment, const-to-runtime equivalence,
`
``
`873`
`+
// reject any of these possible situations from happening.
`
``
`874`
`+
#[inline]
`
``
`875`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
`876`
`+
const fn ct_u128_to_f128(ct: u128) -> f128 {
`
``
`877`
`+
match f128::classify_bits(ct) {
`
``
`878`
`+
FpCategory::Subnormal => {
`
``
`879`
`+
panic!("const-eval error: cannot use f128::from_bits on a subnormal number")
`
``
`880`
`+
}
`
``
`881`
`+
FpCategory::Nan => {
`
``
`882`
`+
panic!("const-eval error: cannot use f128::from_bits on NaN")
`
``
`883`
`+
}
`
``
`884`
`+
FpCategory::Infinite | FpCategory::Normal | FpCategory::Zero => {
`
``
`885`
`+
// SAFETY: It's not a frumious number
`
``
`886`
`+
unsafe { mem::transmute::<u128, f128>(ct) }
`
``
`887`
`+
}
`
``
`888`
`+
}
`
``
`889`
`+
}
`
``
`890`
`+`
``
`891`
`+
#[inline(always)] // See https://github.com/rust-lang/compiler-builtins/issues/491
`
``
`892`
`+
fn rt_u128_to_f128(x: u128) -> f128 {
`
``
`893`
`` +
// SAFETY: `u128` is a plain old datatype so we can always... uh...
``
``
`894`
`+
// ...look, just pretend you forgot what you just read.
`
``
`895`
`+
// Stability concerns.
`
``
`896`
`+
unsafe { mem::transmute(x) }
`
``
`897`
`+
}
`
``
`898`
`+
intrinsics::const_eval_select((v,), ct_u128_to_f128, rt_u128_to_f128)
`
`696`
`899`
`}
`
`697`
`900`
``
`698`
`901`
`/// Return the memory representation of this floating point number as a byte array in
`
`@@ -715,8 +918,9 @@ impl f128 {
`
`715`
`918`
```` /// ```
716
919
`#[inline]
`
717
920
`#[unstable(feature = "f128", issue = "116909")]
`
``
921
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
718
922
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
719
``
`-
pub fn to_be_bytes(self) -> [u8; 16] {
`
``
923
`+
pub const fn to_be_bytes(self) -> [u8; 16] {
`
720
924
`self.to_bits().to_be_bytes()
`
721
925
`}
`
722
926
``
`@@ -740,8 +944,9 @@ impl f128 {
`
740
944
```` /// ```
`741`
`945`
`#[inline]
`
`742`
`946`
`#[unstable(feature = "f128", issue = "116909")]
`
``
`947`
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
`743`
`948`
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
`744`
``
`-
pub fn to_le_bytes(self) -> [u8; 16] {
`
``
`949`
`+
pub const fn to_le_bytes(self) -> [u8; 16] {
`
`745`
`950`
`self.to_bits().to_le_bytes()
`
`746`
`951`
`}
`
`747`
`952`
``
`@@ -776,8 +981,9 @@ impl f128 {
`
`776`
`981`
```` /// ```
777
982
`#[inline]
`
778
983
`#[unstable(feature = "f128", issue = "116909")]
`
``
984
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
779
985
`#[must_use = "this returns the result of the operation, without modifying the original"]
`
780
``
`-
pub fn to_ne_bytes(self) -> [u8; 16] {
`
``
986
`+
pub const fn to_ne_bytes(self) -> [u8; 16] {
`
781
987
`self.to_bits().to_ne_bytes()
`
782
988
`}
`
783
989
``
`@@ -803,7 +1009,8 @@ impl f128 {
`
803
1009
`#[inline]
`
804
1010
`#[must_use]
`
805
1011
`#[unstable(feature = "f128", issue = "116909")]
`
806
``
`-
pub fn from_be_bytes(bytes: [u8; 16]) -> Self {
`
``
1012
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
1013
`+
pub const fn from_be_bytes(bytes: [u8; 16]) -> Self {
`
807
1014
`Self::from_bits(u128::from_be_bytes(bytes))
`
808
1015
`}
`
809
1016
``
`@@ -829,7 +1036,8 @@ impl f128 {
`
829
1036
`#[inline]
`
830
1037
`#[must_use]
`
831
1038
`#[unstable(feature = "f128", issue = "116909")]
`
832
``
`-
pub fn from_le_bytes(bytes: [u8; 16]) -> Self {
`
``
1039
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
1040
`+
pub const fn from_le_bytes(bytes: [u8; 16]) -> Self {
`
833
1041
`Self::from_bits(u128::from_le_bytes(bytes))
`
834
1042
`}
`
835
1043
``
`@@ -865,7 +1073,8 @@ impl f128 {
`
865
1073
`#[inline]
`
866
1074
`#[must_use]
`
867
1075
`#[unstable(feature = "f128", issue = "116909")]
`
868
``
`-
pub fn from_ne_bytes(bytes: [u8; 16]) -> Self {
`
``
1076
`+
#[rustc_const_unstable(feature = "const_float_bits_conv", issue = "72447")]
`
``
1077
`+
pub const fn from_ne_bytes(bytes: [u8; 16]) -> Self {
`
869
1078
`Self::from_bits(u128::from_ne_bytes(bytes))
`
870
1079
`}
`
871
1080
``