ten*_*our 30 language-agnostic floating-point negative-zero
IEEE浮点数有一个位用于指示符号,这意味着您可以在技术上具有零(+0和-0)的不同二进制表示.我是否可以在C中进行算术运算,从而产生负零浮点值?
这个问题的灵感来自于另一个问题是否可以安全地比较0.0f使用==,我还想知道是否还有其他方法来表示零,这会导致float1 == 0.0f看似完全相等的值.
[编辑]请不要评价比较花车的平等安全性!我并没有试图添加那些重复的问题.
Ros*_*ron 22
根据标准,负零存在,但它等于正零.对于几乎所有目的,两者的行为方式相同,许多人认为负面的存在是一个实现细节.但是,有些功能表现得完全不同,即除法和atan2:
#include <math.h>
#include <stdio.h>
int main() {
double x = 0.0;
double y = -0.0;
printf("%.08f == %.08f: %d\n", x, y, x == y);
printf("%.08f == %.08f: %d\n", 1 / x, 1 / y, 1 / x == 1 / y);
printf("%.08f == %.08f: %d\n", atan2(x, y), atan2(y, y), atan2(x, y) == atan2(y, y));
}
Run Code Online (Sandbox Code Playgroud)
此代码的结果是:
0.00000000 == -0.00000000: 1
1.#INF0000 == -1.#INF0000: 0
3.14159265 == -3.14159265: 0
Run Code Online (Sandbox Code Playgroud)
这意味着代码可以正确处理某些限制,而无需显式处理.不确定依靠此功能接近极限的值是一个好主意,因为简单的计算错误可能会改变符号并使值远远不正确,但如果您避免计算,您仍然可以利用它改变标志.
Ste*_*non 13
我是否可以在C中进行算术运算,从而产生负零浮点值?
当然:
float negativeZero = -10.0e-30f * 10.0e-30f;
Run Code Online (Sandbox Code Playgroud)
乘法的数学精确结果不能表示为浮点值,因此它舍入到最接近的可表示值,即-0.0f.
负零的语义由IEEE-754标准明确定义; 在算术表达式中,它的行为与零的行为不同的唯一真实可观察方式是,如果除以它,你将得到一个不同的无穷大符号.例如:
1.f / 0.f --> +infinity
1.f / -0.f --> -infinity
Run Code Online (Sandbox Code Playgroud)
比较和加法和减法-0.f给出与它们相同的结果+0.f(在默认的舍入模式中).乘法可以保留零的符号,但如上所述,它通常是不可观察的.
有一些数学库函数的行为可以根据零的符号而变化.例如:
copysignf(1.0f, 0.0f) --> 1.0f
copysignf(1.0f,-0.0f) --> -1.0f
Run Code Online (Sandbox Code Playgroud)
这在复杂的功能中更常见:
csqrtf(-1.0f + 0.0f*i) --> 0.0f + 1.0f*i
csqrtf(-1.0f - 0.0f*i) --> 0.0f - 1.0f*i
Run Code Online (Sandbox Code Playgroud)
但是,一般情况下,您不必担心负零.
有几个简单的算术运算会导致负零答案(至少在我测试过的 i386/x64/ARMv7/ARMv8 系统上):
当我编写一个优化器来简化算术表达式时,这些让我感到惊讶。如果 b 恰好为负(正确答案是 -0),将“ a = b * 0 ”优化为“ a = 0 ”将导致错误答案(+0)。