检查数字是否可以精确表示为`f32`

时间:2019-02-20 09:02:10

标签: rust floating-point ieee-754

我想知道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已经存在时,无法知道它的值是否是预期的。因此,我们必须以某种方式找出创建浮点值并与“理想化”值进行比较的情况?

有什么方法可以检查一个值是否可以准确地表示为f32

2 个答案:

答案 0 :(得分:3)

Rational中的类型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 :(得分:0)

以更高的精度进行所需的计算(f64是显而易见的且最快的,但是还有其他选择:例如f128BigDecimalrug's {{1} }或rationaletc.),然后检查结果是否等于转换为float并返回的结果。

为示例而假设f32

f64

当然,正如乔乔内特(Jojonete)的评论所指出的那样,这些计算的结果最终可能完全可以表示为d.is_finite() && (d as f32) as f64 == d ,即使确切的结果不是。因此,所需的数据类型将取决于计算。例如。

  

1 / 256、2 / 256、3 / 256,... 254/256和255/256

f32肯定是准确的(rug::rational也是如此,但是您至少需要“思考一下浮点数如何工作并找出这种方式”)。