c++ 中的浮点数 a = -a 和 a *= -1 有区别吗?
Is there a difference between a = -a and a *= -1 for floats in c++?
对于 signed int、float 和 double 等类型?因为,如果我没记错的话(一个很大的如果),这是一个稍微翻转的问题,我想是否有一个明确的操作可以使代码 运行 更快?
编辑: 好吧,只是浮点型,int部分是我忘记动脑了,sorry)
-a
和 a * -1
是不同的操作。1 C++ 标准中没有任何内容公开要求实现为它们产生不同的结果,因此编译器可以将它们视为相同的。 C++ 标准中的任何内容都不需要实现对它们进行相同的处理,因此编译器可能会以不同的方式处理它们。
C++ 标准在指定浮点运算方面非常宽松。 C++ 实现可以将一元 -
视为数学运算,因此 -a
等价于 0-a
。另一方面,C++ 实现可以将一元 -
视为 IEEE-754 negate(x) 操作,每个IEEE 754-2008 5.5.1:
… negate(x) copies a floating-point operand x to a destination in the same format, reversing the sign bit. negate(x) is not the same as subtraction(0, x)…
差异包括:
- 取反是位级操作;它翻转符号位,不会发出 1 异常信号,即使操作数是信号 NaN,并且可能传播非规范编码(与十进制格式相关)。
- 减法和乘法是数学运算;他们将发出 2 异常情况信号,并且不会传播非规范结果。
因此,您可能会发现编译器为 a = -a;
生成的 XOR 指令仅翻转符号位,但为 a *= -1;
生成乘法指令。只有当实现不支持浮点标志、陷阱、信号 NaN 或任何其他使否定和 subtraction/multiplication 可区分的东西时,它才应该为 a *= -1;
生成 XOR 指令。
Godbolt shows that x86-64 Clang 11.0.0 with default options uses xor
for -a
and mulss
for a * -1
. But x86-64 GCC 10.2 对两者都使用 xorps
。
脚注
1 我在这里隔离了 -
和 *
操作;作业部分不感兴趣。
2 这里使用 IEEE-754 意义上的“信号”,表示出现异常情况的指示。这可能会导致出现一个标志,并且可能会导致影响程序控制的陷阱。它与C++信号不一样,虽然陷阱可能会导致C++信号。
对于 signed int、float 和 double 等类型?因为,如果我没记错的话(一个很大的如果),这是一个稍微翻转的问题,我想是否有一个明确的操作可以使代码 运行 更快?
编辑: 好吧,只是浮点型,int部分是我忘记动脑了,sorry)
-a
和 a * -1
是不同的操作。1 C++ 标准中没有任何内容公开要求实现为它们产生不同的结果,因此编译器可以将它们视为相同的。 C++ 标准中的任何内容都不需要实现对它们进行相同的处理,因此编译器可能会以不同的方式处理它们。
C++ 标准在指定浮点运算方面非常宽松。 C++ 实现可以将一元 -
视为数学运算,因此 -a
等价于 0-a
。另一方面,C++ 实现可以将一元 -
视为 IEEE-754 negate(x) 操作,每个IEEE 754-2008 5.5.1:
… negate(x) copies a floating-point operand x to a destination in the same format, reversing the sign bit. negate(x) is not the same as subtraction(0, x)…
差异包括:
- 取反是位级操作;它翻转符号位,不会发出 1 异常信号,即使操作数是信号 NaN,并且可能传播非规范编码(与十进制格式相关)。
- 减法和乘法是数学运算;他们将发出 2 异常情况信号,并且不会传播非规范结果。
因此,您可能会发现编译器为 a = -a;
生成的 XOR 指令仅翻转符号位,但为 a *= -1;
生成乘法指令。只有当实现不支持浮点标志、陷阱、信号 NaN 或任何其他使否定和 subtraction/multiplication 可区分的东西时,它才应该为 a *= -1;
生成 XOR 指令。
Godbolt shows that x86-64 Clang 11.0.0 with default options uses xor
for -a
and mulss
for a * -1
. But x86-64 GCC 10.2 对两者都使用 xorps
。
脚注
1 我在这里隔离了 -
和 *
操作;作业部分不感兴趣。
2 这里使用 IEEE-754 意义上的“信号”,表示出现异常情况的指示。这可能会导致出现一个标志,并且可能会导致影响程序控制的陷阱。它与C++信号不一样,虽然陷阱可能会导致C++信号。