C实现中的浮点零(IEEE 754不变量?)

时间:2016-07-13 11:40:24

标签: c numeric ieee-754 zero

我有一个跟随C表达式(变量是32位浮点数)

float result = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)

假设x0==x1y0==y1,(和==我的意思是二进制表示身份),我可以依赖表达式必须评估为零的事实(如, float的所有位都设置为0)?换句话说,我可以假设跟随不变量总是持有吗?

memcmp(&a, &b, sizeof(float) == 0 => memcmp(a-b, (uint32_t)0, sizeof(float)) == 0
0*a == 0.0

可以安全地假设所有值都是有限数(无INFINITY或NaN)。

编辑:正如答案中所指出的,乘以0会产生带符号的零。我是否仍然可以依赖使用FP比较规则表达式的结果等于0.0的事实,即:

(result == 0.0) 

编辑1:通过memcmp调用替换类型转换以更好地说明问题。

P.S。我只是将我的代码限制在兼容的C11编译器中,以防它有任何区别。如果这对我的情况有帮助,我也愿意依赖 STDC_IEC_559 支持。

1 个答案:

答案 0 :(得分:4)

提及C11只是混淆了您的问题,因为任何C标准都不要求IEEE 754。

话虽如此,假设IEEE 754 32位浮点数并且对x2y2没有假设(除了它们不是无限或NaN),你不能假设所有的结果的位数为0. IEEE 754数字有两个零,一个为负,一个为正,如果表达式(y2 - y0) - (x2 - x0)为负,则将其与零相乘的结果将为负零。

我们可以用这个简短的例子来测试它:

#include <stdio.h>
#include <stdint.h>

int
main(int argc, char **argv)
{
    union {
        float f;
        uint32_t i;
    } foo;

    float a = 0;
    float b = -1;

    foo.f = a * b;
    printf("0x%x\n", foo.i);

    return 0;
}

结果(注意没有优化,因为我不希望编译器聪明):

$ cc -o foo foo.c && ./foo
0x80000000

哦,我刚刚注意到你的问题的第二部分“换句话说”实际上并不是因为它是一个不同的问题。

首先:

(*(uint32_t*)(&a) == *(uint32_t*)(&b))
由于a == b

与浮点数不等同于-0 == 0。由此,假设的另一部分因为-0 - 0给你-0而分崩离析。我无法进行任何其他相等的减法生成负零,但这并不意味着它不可能,我很确定标准不会对所有实现的减法执行相同的算法,所以a标志位可能会以某种方式潜入那里。