2011-10-19 27 views
1

我一直摔跤與PHP的小區(浮法)功能讓我稍微錯誤的結果 - 考慮以下幾點:PHP小區給出錯誤的結果,如果輸入的是不帶小數

$num = 2.7*3; //float(8.1) 
$num*=10; //float(81) 
$num = ceil($num); //82, but shouldn't this be 81?? 
$num/=10; //float(8.2) 

我有一些這可能有任何小數位數,我需要它四捨五入到小數點後一位。 即8.1應該是8.1,8.154應該是8.2,8應該保留爲8.

我到那裏的方式是將數乘以10,ceil(),然後除以十但正如您所看到的,在某些情況下,我會添加額外的.1。

任何人都可以告訴我爲什麼發生這種情況,以及如何解決它?

任何幫助,不勝感激編輯

:必須的+ = 10,而不是* = 10:S

編輯2: 我並沒有明確提到這一點,但我需要總是四捨五入小數,從來沒有下降 - 這個答案是迄今爲止最接近:

rtrim(rtrim(sprintf('%.1f', $num), '0'), '.'); 

然而,當我需要3.9時,輪數3.84下降到3.8。 對不起,這不是更清晰:(

最後編輯:最後我做什麼是這個

$num = 2.7*3; //float(8.1) 
$num*=10; //float(81) 
$num = ceil(round($num, 2)); //81 :) 
$num/=10; //float(8.1) 

其中一期工程:)

回答

2

這很可能是由於浮點錯誤。

您可能有運氣嘗試此方法來代替。

<?php 
$num = 2.7*3; 
echo rtrim(rtrim(sprintf('%.1f', $num), '0'), '.'); 
+0

這給了2位小數,我需要1 - 此代碼工作:回聲rtrim(rtrim(sprintf('%。1f',$ num),'0'),'。');否則,很好的答案,謝謝 – jammypeach

+0

哦,我讀了「兩位小數」出於某種原因。 – erisco

0

的問題是,浮點數很難預料他們會成爲什麼樣的人。你的2.7 * 3可能會出現類似於81.0000000000000000001,ceil()高達82.對於這種事情,你必須用一些精確檢查來包裝你的ceil/round/floor調用,以處理那些額外的微觀差異。

+0

你能提供一個例子嗎? – jammypeach

2

花車可以是變幻莫測的東西。並非所有實數都可以用有限數量的二進制位正確表示。
事實證明,0.7的小數部分就是其中一個數字(在0.10之後出現一個無限重複「1100」的數字)。你最終的數字會略高於0.7,所以當你乘以10時,你的數字會略高於7.

你可以做的是做一個理智的檢查。把你的浮點數減去它的整數形式。如果結果值小於0.0001,則認爲它是內部舍入誤差並保持原樣。如果結果大於0.0001,則正常應用ceil()。

編輯:一個有趣的例子,你可以做的,如果你在窗口顯示這是打開內置的計算器應用程序。放入「4」,然後應用平方根函數(其中y = 0.5)。你會看到它正確顯示「2」。現在,從它減去2,你會看到你沒有0作爲結果。當它試圖計算4的平方根時,這是由內部舍入誤差造成的。當更早地顯示數字2時,它知道那些非常遠的尾數可能是舍入誤差,但是當這些都剩下時,它會得到有點困惑。

(之前任何人得到在我這,我明白,這是過於簡單化了,但儘管如此我認爲這是一個不錯的例子。)

0

使用%f代替%.1f

echo rtrim(rtrim(sprintf('%f', $num), '0'), '.'); 
0

爲什麼不試試這個:

$num = 2.7*3; 
$num *= 100; 
$num = floor($num); 
$num /= 10; 
$num = ceil($num); 
$num /= 10;