【问题标题】:Why does MSVS not optimize away +0?为什么 MSVS 不优化 +0?
【发布时间】:2013-05-04 19:54:57
【问题描述】:

这个question 展示了一个非常有趣的现象:denormalized 浮点数会使代码减慢一个数量级以上。

accepted answer 很好地解释了这种行为。但是,有一条评论,目前有 153 票,我无法找到满意的答案:

在这种情况下,为什么编译器不直接删除 +/- 0?!? – 迈克尔·多根

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


§5.2.4.2.2

实现可能会给出零和非浮点值 数字(例如无穷大和 NaN)是一个符号或可能会留下它们 未签名。

【问题讨论】:

  • 这在the answer 的最后一个 cmets 中回答了链接问题:“@s73v3r:+0.f 无法优化,因为浮点数为负 0,并且将 +0.f 添加到 -.0f 的结果是 +0.f。因此添加 0.f 不是恒等运算,无法优化。- Eric Postpischil"
  • 并且要清楚 - 不是 +0.f 或 -0.f 是非规范化的 - 它是数组中添加零的值是非规范化的(并导致减速)。
  • 我认为编辑不会改变任何东西。 MSVC 使用的浮点实现使用有符号零。这可能不是 C 标准所要求的,但可能是 IEEE 754 所要求的(老实说,我不知道)。但是,/fp:fast 选项可能会导致编译器优化+0.f - 我不知道。
  • 我不认为 C 或 C++ 标准规定了浮点零应该如何表示。但是,我的理解是 IEEE 754 指定零由所有零位表示(负零情况下的符号位除外)。但我与浮点专家相去甚远,对 IEEE 标准的细节几乎一无所知。所以,我在这条评论中所说的可能不是很有用。
  • 现在有 153 票。

标签: c floating-point


【解决方案1】:

编译器无法消除浮点正零的添加,因为它不是恒等运算。按 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] 中的次正规值的算术运算,因此足以减慢程序的速度。

【讨论】:

    【解决方案2】:

    非规范化的不是零常数0.0f,而是循环每次迭代接近零的值。随着它们越来越接近于零,它们需要更高的精度来表示,因此需要进行非规范化。在original question 中,这些是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 也有区别,这就回答了主要问题。
    猜你喜欢
    • 1970-01-01
    • 2018-11-01
    • 2014-08-29
    • 2013-06-17
    • 2013-05-26
    • 2019-03-08
    • 2010-09-12
    • 2021-11-22
    相关资源
    最近更新 更多