为什么MSVS没有优化+0?

时间:2013-05-10 07:11:52

标签: c floating-point

这个question演示了一个非常有趣的现象:denormalized浮动会使代码速度降低一个数量级以上。

行为在accepted answer中得到了很好的解释。但是,有一条评论,目前有48条评论,我找不到满意的答案:

  

为什么编译器在这种情况下不会丢弃+/- 0? -    Michael Dorgan

旁注:我的印象是0f是/必须是完全可表示的(此外 - 它的二进制表示必须全为零),但在c11标准中找不到这样的声明。证明这一点的引用,或反驳这一主张的论点,将是最受欢迎的。无论如何, Michael 的问题是这里的主要问题。


§5.2.4.2.2

  

实现可以给出零和不是浮点的值   数字(如无穷大和NaNs)是一个标志或可能留下它们   无符号的。

2 个答案:

答案 0 :(得分:54)

编译器无法消除浮点正零的添加,因为它不是标识操作。按IEEE 754规则,加+0的结果。到-0。不是-0。;它是+0。

编译器可以消除+0的减法。或者添加-0。因为那些是身份操作。

例如,当我编译它时:

double foo(double x) { return x + 0.; }

使用Apple GNU C 4.2.1在Intel Mac上使用-O3,生成的汇编代码包含addsd LC0(%rip), %xmm0。当我编译它时:

double foo(double x) { return x - 0.; }

没有添加指令;程序集只返回其输入。

因此,原始问题中的代码可能包含此语句的添加指令:

y[i] = y[i] + 0;

但不包含此声明的说明:

y[i] = y[i] - 0;

但是,第一个语句涉及y[i]中具有次正规值的算术,因此减慢程序就足够了。

答案 1 :(得分:1)

被归一化的不是零常数0.0f,而是每次循环迭代时接近零的值。随着它们越来越接近于零,它们需要更高的精度来表示,因此需要进行非规范化。在original question中,这些是y[i]的值。

慢速和快速版本之间的关键区别在于语句y[i] = y[i] + 0.1f;。一旦执行此行,浮点数中的额外精度就会丢失,并且不再需要代表该精度的非规范化。之后,y[i]上的浮点运算将保持快速状态,因为它们没有被非规范化。

为什么添加0.1f时会失去额外的精度?因为浮点数只有很多有效数字。假设您有足够的存储空间来存储三个有效数字,然后是0.00001 = 1e-50.00001 + 0.1 = 0.1,至少对于此示例浮点格式而言,因为它没有空间存储{{1}中的最低有效位}。