strtof = strtod后面跟着强制转换吗?

7
假设您有一个字符串,如“0.1”,它只能近似表示为二进制浮点数,并且您想将其转换为单精度浮点数。可以这样做:
strtof(s, 0);

或者

(float)strtod(s, 0);

直观地说,这两种方法应该得到相同的结果,但是在所有情况下直觉是否正确呢?或者有没有一些边缘情况,第二种方法通过两次舍入与第一种方法略有不同的结果呢?


2
无论你做什么,二进制计算机上的浮点数总是会很棘手。除非你在一个内存严重受限的系统上,否则根本没有必要使用float,而应始终使用double - Some programmer dude
1
或者说,第二种形式是否存在一些边缘情况,通过两次舍入,与第一种形式略有不同的结果?我不知道有什么方法可以证明没有这样的边缘情况。即使您可以证明一个正确实现的系统不会有这样的边缘情况,您也无法证明某些未来的实现已经正确完成。如果有人使用gcc -funsafe-math-optimizations ...进行编译怎么办?(-ffast-math设置了-funsafe-math-optimizations等...) - Andrew Henle
2
好消息是现在存在这样的边缘情况,并且可以展示出来,从而提供了一个明确的答案,但是你的论点非常奇怪。如果问题是“我能确定 int x = 1 + 1; 设置 x 为 2 吗?”你会认为没有办法确定未来的 C 编译器不会搞砸它吗?不会的,如果编译器没有将 x 设置为 2,那么它就不是 C 编译器。(是的,gcc -ffast-math 不是 C 编译器,因为 GCC 的开发人员会第一个告诉你。) - Pascal Cuoq
1
@PascalCuoq 浮点运算中的边角案例错误并不罕见(不像搞砸 1 + 1 那样……),我认为对于那些对精确浮点结果感兴趣到发帖提问的人来说,应该考虑到这一点。 - Andrew Henle
2个回答

6

C标准对strtodstrtof的规范不够明确。它留下了可能性,即strtof始终、很频繁或从不返回(float)strtod。(本段引用了标准的另一部分,其中包含该段落,该段落指出“结果是最接近可表示值、或者是最接近最接近可表示值的较大或较小可表示值之一,以实现定义的方式选择”)。

typicalstrtodstrtof 实现分别返回最接近传递给它们的十进制表示的 double 和最接近的 float。当这些函数以这种方式运行时,那么 strtof(s, 0) 几乎总是与 (float)strtod(s, 0) 相同。它们不相同的十进制表示被称为 double-rounding problem,因为先将其四舍五入到 double,再四舍五入到 float,会产生与直接四舍五入到float不同的结果。请注意,当发生这种情况时,strtof 的结果更加准确。中间舍入使错误略大于半个 ULP 而不是略小于半个 ULP。

在将数字从 double 转换为 float 时,出现双重舍入问题的十进制表示的一个例子是 1.01161128282547(取自 这个测验)。最接近的 double 正好位于两个 float 之间。直接舍入到 float 可以得到最接近的 float,而通过最接近的 double 则产生另一个 float


3
注意:printf("%a\n", 1.01161128282547); 的输出结果为 0x1.02f8f5p+0,这有助于说明“最接近的双精度浮点数恰好处于两个单精度浮点数之间的中间位置”。 - chux - Reinstate Monica
2
@chux 实际上,已经熟悉十六进制浮点表示法的人可以使用此代码片段来研究1.01161128282547的属性:https://gcc.godbolt.org/z/7WmAUu - Pascal Cuoq

0

x86 FPU 总是使用 80 位浮点数,无论您使用什么类型。甚至在从 double 转换为 float 时可能会有额外的运行时成本。

我不确定,但 strtof() 可以作为 strtod() 的包装器实现,因此在您的位置上,我最好使用 strtof(),而不是调用函数进行解析为 double,然后强制转换为 float,以表明您的意图。如果您不信任编译器并希望优化代码,则可能使用 (float)strtod() 可以节省一些额外的性能,减少 call/ret 指令。


2
这个回答的第一句话已经非常过时了。现在不是1986年了,x86处理器多年来已经有处理binary32和binary64的指令。对于大多数操作系统来说,迁移到64位是重新开始浮点ABI的机会。https://gcc.godbolt.org/z/sTXsFE - Pascal Cuoq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接