检查一个数字是否可以精确表示为“f32”
Check if a number is exactly representable as `f32`
我想知道值 1/256、2/256、3/256、... 254/256 和 255/256 是否可以精确表示为 f32
。现在,聪明的人会考虑浮点数的工作原理并找出答案。但我想在程序中检查一下。我要检查的所有数字都是分数,我控制这些值(即没有用户输入)。
我是从这个开始的:
for n in 1u8..=255 {
let f = (n as f32) / 256.0;
println!("{}", f);
}
但是现在呢?我尝试打印数字以查看是否有大量重复出现的数字,但这并不总是有效。例如,不能精确表示的 0.4:
println!("{}", 0.4); // prints "0.4"
println!("{:.20}", 0.4); // prints "0.40000000000000002220"
这里我们必须手动提高精度才能看到问题。在任何情况下,查看字符串输出似乎都不是最佳解决方案。
起初我认为 f32
上可能有一个方法,但这没有多大意义,不是吗?因为当 f32
已经存在时,无法知道它的值是否有意为之。所以我们必须在创建浮点值时找出并与 "idealized" 值进行比较?
有什么方法可以检查一个值是否可以精确表示为 f32
?
以更高的精度进行您想要的计算(f64
是最明显和最快的,但也有其他选择:例如 f128
, BigDecimal
, rug
's rational
or float
, etc.),然后检查结果是否等于自身转换为f32
然后回来。
为了举例,假设 f64
d.is_finite() && (d as f32) as f64 == d
当然,正如 Jojonete 的评论所指出的那样,这些计算的结果最终可能会精确表示为 f32
,即使实际结果并非如此。所以你想要的数据类型将取决于计算。例如。
1/256, 2/256, 3/256, ... 254/256 and 255/256
rug::rational
肯定是准确的(f64
也是如此,但是你至少需要 "think about how floating point numbers work and find out that way" 一点)。
类型Rational
from the rug
crate可以精确表示分数。它还实现了 PartialEq<f32>
,因此您可以直接将精确表示与 f32
进行比较,以检查它们是否相等。
for n in 1u8..=255u8 {
let rat = Rational::from((n, 256));
let f = (n as f32) / 256.0;
println!("{}/256 -> {}", n, rat == f);
}
正如您从输出中看到的那样,您要测试的数字确实可以精确表示为 f32
。
要获得更多更有趣的输出,请尝试 1 / n
:
for n in 1u8..=255u8 {
let rat = Rational::from((1, n));
let f = 1.0 / (n as f32);
println!("1/{} -> {}", n, rat == f);
}
这表明只有分母为 2 的幂的分数才能准确表示。
我想知道值 1/256、2/256、3/256、... 254/256 和 255/256 是否可以精确表示为 f32
。现在,聪明的人会考虑浮点数的工作原理并找出答案。但我想在程序中检查一下。我要检查的所有数字都是分数,我控制这些值(即没有用户输入)。
我是从这个开始的:
for n in 1u8..=255 {
let f = (n as f32) / 256.0;
println!("{}", f);
}
但是现在呢?我尝试打印数字以查看是否有大量重复出现的数字,但这并不总是有效。例如,不能精确表示的 0.4:
println!("{}", 0.4); // prints "0.4"
println!("{:.20}", 0.4); // prints "0.40000000000000002220"
这里我们必须手动提高精度才能看到问题。在任何情况下,查看字符串输出似乎都不是最佳解决方案。
起初我认为 f32
上可能有一个方法,但这没有多大意义,不是吗?因为当 f32
已经存在时,无法知道它的值是否有意为之。所以我们必须在创建浮点值时找出并与 "idealized" 值进行比较?
有什么方法可以检查一个值是否可以精确表示为 f32
?
以更高的精度进行您想要的计算(f64
是最明显和最快的,但也有其他选择:例如 f128
, BigDecimal
, rug
's rational
or float
, etc.),然后检查结果是否等于自身转换为f32
然后回来。
为了举例,假设 f64
d.is_finite() && (d as f32) as f64 == d
当然,正如 Jojonete 的评论所指出的那样,这些计算的结果最终可能会精确表示为 f32
,即使实际结果并非如此。所以你想要的数据类型将取决于计算。例如。
1/256, 2/256, 3/256, ... 254/256 and 255/256
rug::rational
肯定是准确的(f64
也是如此,但是你至少需要 "think about how floating point numbers work and find out that way" 一点)。
类型Rational
from the rug
crate可以精确表示分数。它还实现了 PartialEq<f32>
,因此您可以直接将精确表示与 f32
进行比较,以检查它们是否相等。
for n in 1u8..=255u8 {
let rat = Rational::from((n, 256));
let f = (n as f32) / 256.0;
println!("{}/256 -> {}", n, rat == f);
}
正如您从输出中看到的那样,您要测试的数字确实可以精确表示为 f32
。
要获得更多更有趣的输出,请尝试 1 / n
:
for n in 1u8..=255u8 {
let rat = Rational::from((1, n));
let f = 1.0 / (n as f32);
println!("1/{} -> {}", n, rat == f);
}
这表明只有分母为 2 的幂的分数才能准确表示。