为什么编译器解析源文件中的浮点数的方式与运行时不同?

Why does the compiler parse a floating point number in a source file differently than at runtime?

提问人:Filipe Gonçalves 提问时间:3/27/2015 最后编辑:ShepmasterFilipe Gonçalves 更新时间:12/17/2018 访问量:185

问:

我最近一直在做一些 Rust 项目来学习语言并获得一些乐趣。我正在 Rust 中编写类似于 libconfig 的东西,使用 peg crate 来生成我的解析器。

在过去的一个小时里,我一直在与一个奇怪的错误作斗争,其中从示例配置文件中解析的某些值与预期值不相等。

最终,我将错误范围缩小到以下几点:

fn main() {
    let my_flt = "10.4e-5".parse::<f32>().unwrap();
    let other_flt = 10.4e-5;
    println!("{} == {} -> {}", my_flt, other_flt, my_flt == other_flt);
}

令人惊讶的是,这打印了:

0.000104 == 0.000104 -> 假

在操场上看到它

现在,我知道这一定是与臭名昭著的浮点精度问题有关。我知道,即使两个浮点数在打印时可能看起来相同,但由于各种原因,它们可能会有所不同,但我猜想,从中获取浮点数等同于显式声明一个浮点数并将其初始化为 。显然,我错了,但为什么呢?parse::<f32>("X")X

毕竟,如果我在内部声明并初始化一个浮点数,编译器将不得不执行与生成最终可执行文件时相同的工作。Xparse()

为什么编译器以与运行时函数不同的方式解析源文件中的浮点数?这不应该是一致的吗?我很难解决这个问题!Xparse::<f32>()

精度 浮点转换

评论

4赞 Chris Morgan 3/27/2015
以更高的精度打印(例如),很明显它们是不同的;transmute to 检查字节,是的,第一个是 0x38da1a92,第二个是0x38da1a93。正如结果所预期的那样,尾数相差 1。{:.20}u32
0赞 Shepmaster 3/27/2015
@MatthieuM。好点子。移动并更新了更多信息。

答:

5赞 Shepmaster 3/27/2015 #1

请注意,OP 的特定示例不再失败(在 Rust 1.31.0 中测试)


一个已知问题是标准库和 rustc 词法分析器解析浮点值的方式不同。

标准库最终调用from_str_radix,您可以在那里看到实现。我不确定解析浮点数文字的编译器版本的确切位置但此评论表明它利用了 LLVM:

编译器使用 LLVM 来解析文字,我们不能完全依赖 LLVM 作为我们的标准库。

评论

0赞 Filipe Gonçalves 3/27/2015
这很有意思。我想知道他们是否能以某种方式模仿 LLVM 的行为以使其保持一致。这可能并不容易,但我希望从长远来看,这个问题能得到解决。感谢您的回答!
1赞 Shepmaster 3/27/2015
我认为愿望是这两种实现最终的行为相同。在目前的情况下,也存在一定的性能不足,所以这可能也摆在桌面上。不幸的是,有一个差异的 ULP 可能不是最顶端的。也许您可以了解它并提交补丁!^_^