在IEEE 754中跳过"零测试"检查

dun*_*cks 5 c ieee-754

我在一本关于计算机图形的流行书中读到了这个,

如果程序员利用IEEE规则,有许多数值计算变得更加简单.例如,考虑表达式:

a = 1 /(1/b + 1/c)

这种表达产生于电阻器和透镜.如果被零除导致程序崩溃(在IEEE浮点之前的许多系统中都是如此),则需要两个if语句来检查b或c的小值或零值.相反,对于IEEE浮点数,如果b或c为零,我们将根据需要获得零值.

但有关情况什么b=+0c=-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;
}
Run Code Online (Sandbox Code Playgroud)

chu*_*ica 2

b=+0但是 where和 的情况又如何呢c=-0

通过添加转换-0.0为不分支。+0.00.0

int main(void) {
  double b = +0.0;
  double c = -0.0;
  printf("%e\n", b);
  printf("%e\n", c);
  printf("%e\n", 1.0/(1.0/b + 1.0/c));
  b += 0.0;
  c += 0.0;
  printf("%e\n", 1.0/(1.0/b + 1.0/c));
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出

0.000000e+00
-0.000000e+00
nan
0.000000e+00
Run Code Online (Sandbox Code Playgroud)

[编辑] 另一方面,任何接近0.0但不是的值0.0都可能是数字伪影,而不是准确的电阻值。 上面的代码对于像The issues is -->和-->这样的微小值对仍然存在问题。可以使用更宽的浮点数进行商计算或缩小操作数。b = DBL_TRUE_MIN; c = -b;1.0/tinyInfinity+Infinity + -InfinityNAN

  b += 0.0;
  c += 0.0;
  printf("%Le\n", 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("%e\n", 1.0/(1.0/b + 1.0/c));
Run Code Online (Sandbox Code Playgroud)