使用地板(a / b)是否安全?

时间:2016-11-09 05:00:11

标签: floating-point

在许多编程语言中,有一个名为floor的函数,它接受一个浮点参数(一个double或一个),并返回不大于参数的最大整数。现在我有一个问题:通过调用floor(a / b)获得不大于a / b的最大整数是否安全?我认为浮点计算可能不准确。因此,例如,a / b的确切值可能是2.999999998,但可以计算为3.00000000,然后floor(a / b)得到3,这是不正确的。

2 个答案:

答案 0 :(得分:0)

是的,如果使用IEEE754二进制64格式(即大多数系统上的典型C double)。一个例子是当a = 0.9(其中0.9不能用格式表示,实际上是0.90000000000000002220446049250313080847263336181640625)和b = 0.1(实际上是0.1000000000000000055511151231257827021181583404541015625)时,a/b的真值实际上是

... 8.999999999999999722444243843710880301531638075180891038116311176859261171872

然而,这将四舍五入到9.0,因为它比前一个浮点数更接近9

8.9999999999999982236431605997495353221893310546875

所以floor(a/b)也是9.0

答案 1 :(得分:0)

如果ab是整数(小于幂(2,尾数大小+ 2))或者ab是“完全”,那么这是安全的“代表。

START_UPDATE

可以将问题重新表述为:a/b = n可以a < n*b吗?

这个论点相当复杂,但这个问题的答案是否定的:

如果a < n*ba <= n*b - eps(n*b)/2

最糟糕的情况是eps(n*b)/2接近但小于2的幂。但即使在最坏的情况下,你也有

   a < n*b - n*b*eps(1.0)/4

所以

   a/b exactly evaluated < n - n*eps(1.0)/4
   a/b exactly evaluated < n - eps(n)/4

并且舍入到最近的偶数模式确保

   a/b in floating-point < n

END_UPDATE

现在假设a/b的确切值是一个整数n,具有向下近似a和向上近似b。然后a/b可以在最后一个位置以超过1/2单位向下近似,因此小于n。因此a/b = nfloor(a/b) = n-1的确切值。

以下C ++代码返回与floor((i/1000)/0.001)不同的126个i异常。第一个是0.043/0.001

#include <iostream>
#include <cmath>

int main() {
  double x, y;
  for (int i = 0; i < 1000; ++  i) {
    x = i / 1000.0;
    y = 0.001;
    if (floor(x/y) != (double) i)
       std::cout << i << ' ' << floor(x/y) << '\n';
  }
  std::cout.flush();
}