未验证 提交 63531f51 编写于 作者: K kennytm 提交者: GitHub

Rollup merge of #50342 - fkjogu:euclidean, r=BurntSushi

Document round-off error in `.mod_euc()`-method, see issue #50179

Due to a round-off error the method `.mod_euc()` of both `f32` and `f64` can produce mathematical invalid outputs. If `self` in magnitude is much small than the modulus `rhs` and negative, `self + rhs` in the first branch cannot be represented in the given precision and results into `rhs`. In the mathematical strict sense, this breaks the definition. But given the limitation of floating point arithmetic it can be thought of the closest representable value to the true result, although it is not strictly in the domain `[0.0, rhs)` of the function. It is rather the left side asymptotical limit. It would be desirable that it produces the mathematical more sound approximation of `0.0`, the right side asymptotical limit. But this breaks the property, that `self == self.div_euc(rhs) * rhs + a.mod_euc(rhs)`.

The discussion in issue #50179 did not find an satisfying conclusion to which property is deemed more important. But at least we can document the behaviour. Which this pull request does.
......@@ -574,6 +574,25 @@ fn max() {
assert_eq!((-9.0 as $fty).max($nan), -9.0);
assert!(($nan as $fty).max($nan).is_nan());
}
#[test]
fn mod_euc() {
let a: $fty = 42.0;
assert!($inf.mod_euc(a).is_nan());
assert_eq!(a.mod_euc($inf), a);
assert!(a.mod_euc($nan).is_nan());
assert!($inf.mod_euc($inf).is_nan());
assert!($inf.mod_euc($nan).is_nan());
assert!($nan.mod_euc($inf).is_nan());
}
#[test]
fn div_euc() {
let a: $fty = 42.0;
assert_eq!(a.div_euc($inf), 0.0);
assert!(a.div_euc($nan).is_nan());
assert!($inf.div_euc($inf).is_nan());
assert!($inf.div_euc($nan).is_nan());
assert!($nan.div_euc($inf).is_nan());
}
} }
}
......
......@@ -254,7 +254,14 @@ pub fn div_euc(self, rhs: f32) -> f32 {
/// Calculates the Euclidean modulo (self mod rhs), which is never negative.
///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
/// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
/// most cases. However, due to a floating point round-off error it can
/// result in `r == rhs.abs()`, violating the mathematical definition, if
/// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
/// This result is not an element of the function's codomain, but it is the
/// closest floating point number in the real numbers and thus fulfills the
/// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)`
/// approximatively.
///
/// # Examples
///
......@@ -266,6 +273,8 @@ pub fn div_euc(self, rhs: f32) -> f32 {
/// assert_eq!((-a).mod_euc(b), 1.0);
/// assert_eq!(a.mod_euc(-b), 3.0);
/// assert_eq!((-a).mod_euc(-b), 1.0);
/// // limitation due to round-off error
/// assert!((-std::f32::EPSILON).mod_euc(3.0) != 0.0);
/// ```
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
......
......@@ -230,7 +230,14 @@ pub fn div_euc(self, rhs: f64) -> f64 {
/// Calculates the Euclidean modulo (self mod rhs), which is never negative.
///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
/// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in
/// most cases. However, due to a floating point round-off error it can
/// result in `r == rhs.abs()`, violating the mathematical definition, if
/// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`.
/// This result is not an element of the function's codomain, but it is the
/// closest floating point number in the real numbers and thus fulfills the
/// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)`
/// approximatively.
///
/// # Examples
///
......@@ -242,6 +249,8 @@ pub fn div_euc(self, rhs: f64) -> f64 {
/// assert_eq!((-a).mod_euc(b), 1.0);
/// assert_eq!(a.mod_euc(-b), 3.0);
/// assert_eq!((-a).mod_euc(-b), 1.0);
/// // limitation due to round-off error
/// assert!((-std::f64::EPSILON).mod_euc(3.0) != 0.0);
/// ```
#[inline]
#[unstable(feature = "euclidean_division", issue = "49048")]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册