我有一个跟随C表达式(变量是32位浮点数)
float result = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0)
假设x0==x1
和y0==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 支持。
答案 0 :(得分:4)
提及C11只是混淆了您的问题,因为任何C标准都不要求IEEE 754。
话虽如此,假设IEEE 754 32位浮点数并且对x2
和y2
没有假设(除了它们不是无限或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标志位可能会以某种方式潜入那里。