为什么MSVS没有优化+0?

Vor*_*rac 50 c floating-point

这个问题展示了一个非常有趣的现象:非规范化浮点数使代码减慢了一个数量级以上.

接受的答案中很好地解释了这种行为.但是,有一条评论,目前有48条评论,我找不到满意的答案:

为什么编译器在这种情况下不会降低+/- 0?- 迈克尔多根

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


§5.2.4.2.2

实现可以给零和不是浮点数(例如无穷大和NaN)的值作为符号或者可以使它们保持未签名.

Eri*_*hil 56

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

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

例如,当我编译它时:

double foo(double x) { return x + 0.; }
Run Code Online (Sandbox Code Playgroud)

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

double foo(double x) { return x - 0.; }
Run Code Online (Sandbox Code Playgroud)

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

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

y[i] = y[i] + 0;
Run Code Online (Sandbox Code Playgroud)

但不包含此声明的说明:

y[i] = y[i] - 0;
Run Code Online (Sandbox Code Playgroud)

但是,第一个语句涉及带有y[i]低于正常值的算术,因此减慢程序就足够了.


rem*_*les 8

非标准化的不是零常数0.0f,而是每次循环迭代都接近零的值。随着它们变得越来越接近零,它们需要更高的精度来表示,因此需要非规范化。在原来的问题中,这些是y[i]值。

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

为什么添加时额外的精度会丢失0.1f?因为浮点数只有这么多有效数字。假设您有足够的存储空间来存储三位有效数字,那么0.00001 = 1e-5、 和0.00001 + 0.1 = 0.1,至少对于这个示例浮点格式来说是这样,因为它没有空间来存储 中的最低有效位0.10001

  • 我明白为什么我最近因为没有回答现在出现的问题而收到了反对票。本来这个问题的标题是“为什么MSVS不优化掉+0?而是把它变成非规范化的浮点数?” 我的回答是试图澄清第二部分中的混乱。当然,+0.0f 和 -0.0f 之间也有区别,这回答了主要问题。 (4认同)