2011-01-05 51 views
4

我剛剛閱讀了一篇關於php掛在某些浮點數上的有趣文章,請參閱The RegisterExploring BinaryPHP浮動錯誤:PHP掛在數字值

我從來沒有明確使用花車,我使用number_format()來清理我的輸入和顯示價格的例子。

此外,據我所知,例如形式的所有輸入都是字符串,直到我告訴他們,否則我認爲這個問題不會影響我。

我是對的,還是我需要檢查例如我的服務器上的Wordpress和Squirrelmail安裝,以查看他們是否投出任何東西浮動?或者更好,grep我的服務器上的所有php文件爲float

+2

*(參考)* http://bugs.php.net/bug.php?id=53632 – Gordon 2011-01-05 15:32:36

回答

5

方法來緩解這個問題:

  1. 使用新型CPU。大多數現代的64位CPU都是免疫的(我實際上很難找到允許重現它的主機,因爲它們傾向於使用更現代的硬件)。亞馬遜虛擬機似乎也免疫。
  2. 升級您的PHP版本 - 5.3.5和5.2.17一旦發佈(可能今天)包括修復。
  3. 使用CFLAGS中的-ffloat-store構建(會減慢代碼)。
  4. 手動將patch應用於您的代碼並重建PHP。

尋找具有float可能不會有所幫助zend_strtod代碼在許多與字符串>數轉換方案中使用的發動機。

P.S.此代碼btw是標準的BSD庫strtod代碼,不是PHP獨有的。所以使用這些代碼的其他項目也可能受到影響。

+0

謝謝,但我實際上有一個使用中的不是64位的舊服務器,遷移一切將會是很多工作,儘管它在我的已完成任務列表... – jeroen 2011-01-05 15:52:52

+0

@jeroen:你可以申請這個補丁:http://svn.php.net/viewvc/php/php-src/branches/PHP_5_2/Zend/zend_strtod.c?r1=266327&r2= 307095&視圖=補丁 – StasM 2011-01-05 15:56:33

4

hackernews

的發生是由於IA-32的 80位浮點算術此問題。 簡單修正:向您的CFLAGS添加「-ffloat-store」標誌 。

有問題的 功能,zend_strtod,似乎解析 尾數(2.225 ... 011份)和 指數(-308部分)分開, C> alculate M *的近似10^E 和先後提高 近似值,直到誤差變爲 小於0.5ulp。問題是 這個特定的數字導致 無限循環(即迭代確實不會改善錯誤),但是不在64位FP中。 由於x86-64一般使用SSE2 指令集(使用64位FP) 而不是已棄用的x87,所以它確實沒有這個問題 。

+0

的確,在緊張之前檢查您的弓。如果受到影響,請更新您的提供商。掃描輸入數組應該是最後的手段。 – mario 2011-01-05 15:20:05

+0

@marcog謝謝,但問題是,*簡單*修復是我的一種abracadabra ... – jeroen 2011-01-05 15:22:29

+0

@jeroen'-ffloat-store'是一個C編譯器標誌。用它重新編譯PHP。 – marcog 2011-01-05 15:24:53

1

搜索明確的float-casts不會幫助你 - 在PHP中,變量被視爲它的用途。小例子:

$mystring = "123.45"; //mystring is a string here 
$myvalue = $mystring * 4; // mystring is a float here 
          // and there's no explicit float-cast 

正如你所看到的:升級/修復你的php安裝是避免死亡服務器的唯一保存方式。

編輯:到您的評論:

彩車真的arn't那麼容易。即使像0.7或0.8這樣簡單的數字也不能完全存儲,所以可能會發生這樣的情況,即經過一些計算後,您的0.8就是0.799999999789 ......更糟的是,這只是一個時間問題,直到您遇到問題。

只是作爲一個例子(如果你是一個Windows用戶):

  1. 打開窗戶計算器
  2. 計算的4 sqare根(應爲2)
  3. 。減去2從結果(應該是0但... woooow;))

此錯誤是在Windows計算器,因爲...以往 - 它表明,即使是大公司的可利用失敗花車,但計算器不殺你的系統 - 如果這樣的錯誤可以殺死你的系統(像這樣的PHP錯誤),你必須升級/修復它,沒有。

+0

謝謝,這當然是真的,但如果我所有的變量都是可以解釋爲最大2或4位小數的「浮點數」的「ints」或「strings」,那應該不成問題。 – jeroen 2011-01-05 15:26:14

+0

@jeron:請看看我的編輯,這是太長的評論;) – oezi 2011-01-05 15:38:15

+0

我一定要解決這個問題,我知道一般'浮動',但從我讀過的問題到目前爲止,它似乎並不緊急,因爲簡單的計算似乎不太可能導致這個幻數(我正在談論價格,匯率等)。 – jeroen 2011-01-05 15:47:01

1

這是不夠的,只是搜索的浮動,因爲你再尋找一個明確地把一個變量值的浮動代碼,但你不會找到任何實例,其中,鑄是隱含的。

$d = '2.2250738585072011e-308'; 
$f = float($d); 

是明確的鑄造,但什麼樣的代碼:

$d = '2.2250738585072011e-308'; 
$f = $d + 0.1; 

$d = '2.2250738585072011e-308'; 
if ($d == 0.5) { 

我認爲,這個錯誤也得到修復最新的PHP版本的代碼中,雖然像xampp這樣的軟件包仍然受到影響。

+0

謝謝,但正如我評論@ oezi的答案,這應該不成問題。 – jeroen 2011-01-05 15:26:56

2

正如marcog說,這是一個浮點運算錯誤與數學的x87。如果您想了解更多關於它檢查了GCC的bug,Link

+0

關於浮點數學陷阱的有趣論文,http://hal.archives-ouvertes.fr/hal-00128124 – Kyle 2011-01-05 15:52:25

3

由於快速的解決方法,你可以掃描輸入數組:

foreach(array("_GET","_POST","_REQUEST","_COOKIES") as $G) { 
    if (in_array('2.2250738585072011e-308', $$G)) { 
     header("Status: 422 Unprocessable Entity"); 
     exit; 
    } 
} 

這是足夠的,如果你不使用子陣輸入變量。它會工作,因爲它將float保存爲字符串,輸入數組保存字符串,in_array也在字符串上下文中操作。

但是我如果有值的其它表示還沒有考慮。這是迄今爲止唯一已知的工作,但可能還有更多。所以,更新是更明智的:|

+2

根據「探索二元論」,同一數字的不同形式都有這個問題。 – jeroen 2011-01-05 15:50:48

+1

不同的形式可能會以相同的前綴開頭,如'2.22507385850' – StasM 2011-01-05 16:26:29