2016-11-09 45 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