另一方面,任何接近
这是我在一本关于计算机图形学的畅销书中读到的,
如果程序员利用了IEEE规则,许多数值计算就会变得简单得多。例如,考虑表达式: a = 1/(1/b + 1/c)这种表达式出现在电阻和透镜中。如果除以零导致程序崩溃(在IEEE浮点之前的许多系统中都是如此),则需要两个If语句来检查b或c的小值或零值。相反,使用IEEE浮点,如果b或c为零,我们将得到所需的a的零值。
但是b=+0
和c=-0
的情况呢?然后是a=1/inf-inf=nan
。是书中关于优化的内容有误,还是我误解了什么?看来我们还需要至少检查一次b &C而不是根本没有检查。
编辑评论中的一个建议是对NaN进行事后检查。这是"利用"这些数字类型的惯用方法吗?
bool is_nan(float x) { return x != x; }
float optic_thing(float b, float c) {
float result = 1.0f / (1.0f/b + 1.0f/c);
if (is_nan(result)) result = 0;
return result;
}
但是
b=+0
和c=-0
的情况呢?
将-0.0
转换为+0.0
,不添加0.0
分支。
int main(void) {
double b = +0.0;
double c = -0.0;
printf("%en", b);
printf("%en", c);
printf("%en", 1.0/(1.0/b + 1.0/c));
b += 0.0;
c += 0.0;
printf("%en", 1.0/(1.0/b + 1.0/c));
return 0;
}
输出0.000000e+00
-0.000000e+00
nan
0.000000e+00
另一方面,任何接近
0.0
的值,而不是0.0
,都可能是数字伪影,而不是准确的电阻值。上面的微小的值对如b = DBL_TRUE_MIN; c = -b;
仍然有问题,问题是1.0/tiny
-> Infinity
和+Infinity + -Infinity
-> NAN
。可以使用更宽的浮点数进行商计算,或者缩小操作数。
b += 0.0;
c += 0.0;
printf("%Len", 1.0/(1.0L/b + 1.0L/c));
// Lose some precision, but we are talking about real resistors/lenses here.
b = (float) b + 0.0f;
c = (float) c + 0.0f;
printf("%en", 1.0/(1.0/b + 1.0/c));