2012-01-29 43 views
0

可能重複:
The accuracy of PHP float calculate浮動做,而指數表示:0.8 <0.8

<?php 
    $foo = 0; 
    do { 
     echo "\$foo = $foo".($foo >= 0.8 ? " >= 0.8<br>\n" : " < 0.8<br>\n"); 
     $foo = $foo + 0.1; 
    } while($foo <= 1); 
?> 

導致以下的輸出:

$foo = 0 < 0.8 
$foo = 0.1 < 0.8 
$foo = 0.2 < 0.8 
$foo = 0.3 < 0.8 
$foo = 0.4 < 0.8 
$foo = 0.5 < 0.8 
$foo = 0.6 < 0.8 
$foo = 0.7 < 0.8 
$foo = 0.8 < 0.8 
$foo = 0.9 >= 0.8 
$foo = 1 >= 0.8 

..甚至var_dump並沒有告訴我更多,它是0.8。可怕:

round($foo,1) >= 0.8 

解決了問題 - 幫助感激!

回答

2

爲了補充其他答案:

<?php 
$foo = 0; 

do { 
    echo sprintf('%.16f %s 0.8', $foo, $foo >= 0.8 ? '>=' : '<') . PHP_EOL; 
    $foo = $foo + 0.1; 
} while($foo <= 1); 

產生

0.0000000000000000 < 0.8 
0.1000000000000000 < 0.8 
0.2000000000000000 < 0.8 
0.3000000000000000 < 0.8 
0.4000000000000000 < 0.8 
0.5000000000000000 < 0.8 
0.6000000000000000 < 0.8 
0.7000000000000000 < 0.8 
0.7999999999999999 < 0.8 
0.8999999999999999 >= 0.8 
0.9999999999999999 >= 0.8 

http://ideone.com/ggbMl

去圖;)


你可以使用圓形,這取決於你r案件。但典型的解決方案是使用所謂的machine epsilon。然後,您的情況是

define ('EPS', 1e-15); 
if (abs($foo - 0.8) < EPS) { 
    // ... 

您的EPS的價值顯然取決於你的平臺上,但在條件中使用的價值也取決於你的數量確實爲每個操作會導致更多的舍入誤差算術運算的數量。有關更多信息,請閱讀wiki文章。

+1

非常感謝這個小小的教訓;) – s10z 2012-01-29 11:45:44

+0

不客氣;) – Czechnology 2012-01-29 11:47:42

+0

+1爲更完整的答案(也想過這個,但是因爲我對PHP不熟悉,所以我可能錯過了某些東西或給出錯誤建議) – schnaader 2012-01-29 13:56:33

2

只是標準的浮點舍入的問題。

典型float到字符串轉換扔掉至少顯著二進制數字,所以顯示爲0.8兩個數字不一定相同。並且因爲0.8不能用二進制浮點表示,所以它們都不是0.8

2

的問題是,你可以不完全以二進制浮點代表0.8。你也不能完全代表0.1。因此,使用0.1的不精確值來計算0.8將不太可能匹配0.8的不精確值。

+0

我不不會太瞭解的機制在路上呢。有沒有什麼方法可以使用小數而不使用round()? – s10z 2012-01-29 11:27:15

+0

@Sascha Schulz,看到我的答案結束。 – Czechnology 2012-01-29 11:34:59

+1

@hakre IMO提重複的問題應張貼的評論,而不是編輯成別人的答案。 – CodesInChaos 2012-01-29 21:21:23