2016-11-09 42 views
0

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

+0

是'a'和'b'整数,还是一般浮动? –

+1

如果'a'和'b'是在合理范围内的整数,并且我们可以假设IEEE 754语义,那么是的,这是安全的(大概是因为如果除法结果是一个不太大的整数,那么'a/b '将被无误地计算出来,而如果它不是一个整数并且'a'和'b'不是太大,那么除法结果不能太接近整数。如果这是你感兴趣的情况,请说出来,以便有人可以构建一个适当的答案。 –

+0

我的意思是,a和b是一般的浮点数,但它们是完全表示的。如果难以回答这个问题,回答关于整数也是可以的。 – zhoudu

回答

0

是的,如果使用IEEE754 binary64格式(即在大多数系统上是典型的C double)。一个示例是当a = 0.9(其中,因为0.9不能由格式来表示,实际上是0.90000000000000002220446049250313080847263336181640625)和b = 0.1(实际上0.1000000000000000055511151231257827021181583404541015625)然后a/b真值实际上是

8.999999999999999722444243843710880301531638075180891038116311176859261171872 ...

然而,这将获得四舍五入为9.0,因为它比以前的浮点数

8.9999999999999982236431605997495353221893310546875

接近

所以floor(a/b)也将是9.0

+0

你从哪里得到那个'8.9999999999999997224442438437108803015316380751808910 ...'会被舍入到9.0? –

0

它是安全的,如果ab为整数(小于功率(2,尾数+ 2)的尺寸),或者如果ab是“精确”来表示。

START_UPDATE

的问题可以重新进入:是有可能有a/b = na < n*b

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

如果a < n*b然后a <= 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 = n的确切值,而floor(a/b) = n-1

以下C++代码返回floor((i/1000)/0.001)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(); 
} 
+0

感谢您的回答。但是,那不是我的意思。我的意思是:a和b的确切代表是否安全? – zhoudu

+0

是的,它是安全的。 – Franck

+0

该帖子中的更多解释;你是对的,最初的文章错过了更重要的一点。 – Franck