Skip to content

Commit 28d800c

Browse files
authored
Rollup merge of #95483 - golddranks:improve_float_docs, r=joshtriplett
Improve floating point documentation This is my attempt to improve/solve #95468 and #73328 . Added/refined explanations: - Refine the "NaN as a special value" top level explanation of f32 - Refine `const NAN` docstring: add an explanation about there being multitude of NaN bitpatterns and disclaimer about the portability/stability guarantees. - Refine `fn is_sign_positive` and `fn is_sign_negative` docstrings: add disclaimer about the sign bit of NaNs. - Refine `fn min` and `fn max` docstrings: explain the semantics and their relationship to the standard and libm better. - Refine `fn trunc` docstrings: explain the semantics slightly more. - Refine `fn powi` docstrings: add disclaimer that the rounding behaviour might be different from `powf`. - Refine `fn copysign` docstrings: add disclaimer about payloads of NaNs. - Refine `minimum` and `maximum`: add disclaimer that "propagating NaN" doesn't mean that propagating the NaN bit patterns is guaranteed. - Refine `max` and `min` docstrings: add "ignoring NaN" to bring the one-row explanation to parity with `minimum` and `maximum`. Cosmetic changes: - Reword `NaN` and `NAN` as plain "NaN", unless they refer to the specific `const NAN`. - Reword "a number" to `self` in function docstrings to clarify. - Remove "Returns NAN if the number is NAN" from `abs`, as this is told to be the default behavior in the top explanation.
2 parents e013f9e + dea7765 commit 28d800c

File tree

6 files changed

+182
-68
lines changed

6 files changed

+182
-68
lines changed

library/core/src/num/f32.rs

+60-19
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,15 @@ impl f32 {
393393
pub const MAX_10_EXP: i32 = 38;
394394

395395
/// Not a Number (NaN).
396+
///
397+
/// Note that IEEE-745 doesn't define just a single NaN value;
398+
/// a plethora of bit patterns are considered to be NaN.
399+
/// Furthermore, the standard makes a difference
400+
/// between a "signaling" and a "quiet" NaN,
401+
/// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
402+
/// This constant isn't guaranteed to equal to any specific NaN bitpattern,
403+
/// and the stability of its representation over Rust versions
404+
/// and target platforms isn't guaranteed.
396405
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
397406
pub const NAN: f32 = 0.0_f32 / 0.0_f32;
398407
/// Infinity (∞).
@@ -402,7 +411,7 @@ impl f32 {
402411
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
403412
pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
404413

405-
/// Returns `true` if this value is `NaN`.
414+
/// Returns `true` if this value is NaN.
406415
///
407416
/// ```
408417
/// let nan = f32::NAN;
@@ -455,7 +464,7 @@ impl f32 {
455464
(self == f32::INFINITY) | (self == f32::NEG_INFINITY)
456465
}
457466

458-
/// Returns `true` if this number is neither infinite nor `NaN`.
467+
/// Returns `true` if this number is neither infinite nor NaN.
459468
///
460469
/// ```
461470
/// let f = 7.0f32;
@@ -506,7 +515,7 @@ impl f32 {
506515
}
507516

508517
/// Returns `true` if the number is neither zero, infinite,
509-
/// [subnormal], or `NaN`.
518+
/// [subnormal], or NaN.
510519
///
511520
/// ```
512521
/// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
@@ -622,8 +631,12 @@ impl f32 {
622631
}
623632
}
624633

625-
/// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with
626-
/// positive sign bit and positive infinity.
634+
/// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with
635+
/// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any
636+
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
637+
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
638+
/// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
639+
/// See [explanation of NaN as a special value](f32) for more info.
627640
///
628641
/// ```
629642
/// let f = 7.0_f32;
@@ -640,8 +653,12 @@ impl f32 {
640653
!self.is_sign_negative()
641654
}
642655

643-
/// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with
644-
/// negative sign bit and negative infinity.
656+
/// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with
657+
/// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any
658+
/// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that
659+
/// the bit pattern of NaNs are conserved over arithmetic operations, the result of
660+
/// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
661+
/// See [explanation of NaN as a special value](f32) for more info.
645662
///
646663
/// ```
647664
/// let f = 7.0f32;
@@ -713,47 +730,47 @@ impl f32 {
713730
self * (value / 180.0f32)
714731
}
715732

716-
/// Returns the maximum of the two numbers.
733+
/// Returns the maximum of the two numbers, ignoring NaN.
717734
///
718-
/// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
719-
/// This matches the behavior of libm’s fmax.
735+
/// If one of the arguments is NaN, then the other argument is returned.
736+
/// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs;
737+
/// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
738+
/// This also matches the behavior of libm’s fmax.
720739
///
721740
/// ```
722741
/// let x = 1.0f32;
723742
/// let y = 2.0f32;
724743
///
725744
/// assert_eq!(x.max(y), y);
726745
/// ```
727-
///
728-
/// If one of the arguments is NaN, then the other argument is returned.
729746
#[must_use = "this returns the result of the comparison, without modifying either input"]
730747
#[stable(feature = "rust1", since = "1.0.0")]
731748
#[inline]
732749
pub fn max(self, other: f32) -> f32 {
733750
intrinsics::maxnumf32(self, other)
734751
}
735752

736-
/// Returns the minimum of the two numbers.
753+
/// Returns the minimum of the two numbers, ignoring NaN.
737754
///
738-
/// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs.
739-
/// This matches the behavior of libm’s fmin.
755+
/// If one of the arguments is NaN, then the other argument is returned.
756+
/// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs;
757+
/// this function handles all NaNs the same way and avoids minNum's problems with associativity.
758+
/// This also matches the behavior of libm’s fmin.
740759
///
741760
/// ```
742761
/// let x = 1.0f32;
743762
/// let y = 2.0f32;
744763
///
745764
/// assert_eq!(x.min(y), x);
746765
/// ```
747-
///
748-
/// If one of the arguments is NaN, then the other argument is returned.
749766
#[must_use = "this returns the result of the comparison, without modifying either input"]
750767
#[stable(feature = "rust1", since = "1.0.0")]
751768
#[inline]
752769
pub fn min(self, other: f32) -> f32 {
753770
intrinsics::minnumf32(self, other)
754771
}
755772

756-
/// Returns the maximum of the two numbers, propagating NaNs.
773+
/// Returns the maximum of the two numbers, propagating NaN.
757774
///
758775
/// This returns NaN when *either* argument is NaN, as opposed to
759776
/// [`f32::max`] which only returns NaN when *both* arguments are NaN.
@@ -770,6 +787,9 @@ impl f32 {
770787
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
771788
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
772789
/// Note that this follows the semantics specified in IEEE 754-2019.
790+
///
791+
/// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
792+
/// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
773793
#[must_use = "this returns the result of the comparison, without modifying either input"]
774794
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
775795
#[inline]
@@ -785,7 +805,7 @@ impl f32 {
785805
}
786806
}
787807

788-
/// Returns the minimum of the two numbers, propagating NaNs.
808+
/// Returns the minimum of the two numbers, propagating NaN.
789809
///
790810
/// This returns NaN when *either* argument is NaN, as opposed to
791811
/// [`f32::min`] which only returns NaN when *both* arguments are NaN.
@@ -802,6 +822,9 @@ impl f32 {
802822
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
803823
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
804824
/// Note that this follows the semantics specified in IEEE 754-2019.
825+
///
826+
/// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
827+
/// operand is conserved; see [explanation of NaN as a special value](f32) for more info.
805828
#[must_use = "this returns the result of the comparison, without modifying either input"]
806829
#[unstable(feature = "float_minimum_maximum", issue = "91079")]
807830
#[inline]
@@ -1009,6 +1032,9 @@ impl f32 {
10091032
/// Return the memory representation of this floating point number as a byte array in
10101033
/// big-endian (network) byte order.
10111034
///
1035+
/// See [`from_bits`](Self::from_bits) for some discussion of the
1036+
/// portability of this operation (there are almost no issues).
1037+
///
10121038
/// # Examples
10131039
///
10141040
/// ```
@@ -1027,6 +1053,9 @@ impl f32 {
10271053
/// Return the memory representation of this floating point number as a byte array in
10281054
/// little-endian byte order.
10291055
///
1056+
/// See [`from_bits`](Self::from_bits) for some discussion of the
1057+
/// portability of this operation (there are almost no issues).
1058+
///
10301059
/// # Examples
10311060
///
10321061
/// ```
@@ -1051,6 +1080,9 @@ impl f32 {
10511080
/// [`to_be_bytes`]: f32::to_be_bytes
10521081
/// [`to_le_bytes`]: f32::to_le_bytes
10531082
///
1083+
/// See [`from_bits`](Self::from_bits) for some discussion of the
1084+
/// portability of this operation (there are almost no issues).
1085+
///
10541086
/// # Examples
10551087
///
10561088
/// ```
@@ -1075,6 +1107,9 @@ impl f32 {
10751107

10761108
/// Create a floating point value from its representation as a byte array in big endian.
10771109
///
1110+
/// See [`from_bits`](Self::from_bits) for some discussion of the
1111+
/// portability of this operation (there are almost no issues).
1112+
///
10781113
/// # Examples
10791114
///
10801115
/// ```
@@ -1091,6 +1126,9 @@ impl f32 {
10911126

10921127
/// Create a floating point value from its representation as a byte array in little endian.
10931128
///
1129+
/// See [`from_bits`](Self::from_bits) for some discussion of the
1130+
/// portability of this operation (there are almost no issues).
1131+
///
10941132
/// # Examples
10951133
///
10961134
/// ```
@@ -1114,6 +1152,9 @@ impl f32 {
11141152
/// [`from_be_bytes`]: f32::from_be_bytes
11151153
/// [`from_le_bytes`]: f32::from_le_bytes
11161154
///
1155+
/// See [`from_bits`](Self::from_bits) for some discussion of the
1156+
/// portability of this operation (there are almost no issues).
1157+
///
11171158
/// # Examples
11181159
///
11191160
/// ```

0 commit comments

Comments
 (0)