国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > PHP > 正文

PHP浮點數運算精度的問題

2024-05-04 21:50:28
字體:
來源:轉載
供稿:網友

在用PHP進行浮點數的運算中,遇到一個坑,沒有得到預期中的結果,如下代碼:

$a = 69.1;

$b = $a*100;

$c = $b-6910;

你猜$c的值是多少?$c輸出的值是-9.0949470177293E-13.為什么會這樣?

在PHP官網Float浮點型頁面中,講到:

浮點數的精度

浮點數的精度有限。盡管取決于系統,PHP 通常使用 IEEE 754 雙精度格式,則由于取整而導致的最大相對誤差為 1.11e-16。非基本數學運算可能會給出更大誤差,并且要考慮到進行復合運算時的誤差傳遞。

此外,以十進制能夠精確表示的有理數如 0.1 或 0.7,無論有多少尾數都不能被內部所使用的二進制精確表示,因此不能在不丟失一點點精度的情況下轉換為二進制的格式。這就會造成混亂的結果:例如,floor((0.1+0.7)*10) 通常會返回 7 而不是預期中的 8,因為該結果內部的表示其實是類似 7.9999999999999991118…。

所以永遠不要相信浮點數結果精確到了最后一位,也永遠不要比較兩個浮點數是否相等。如果確實需要更高的精度,應該使用任意精度數學函數或者gmp函數。

那么如何正確處理PHP浮點數計算有誤的問題呢?

  1. $x = 8 - 6.4;  // which is equal to 1.6 
  2. $y = 1.6; 
  3. var_dump($x == $y); // is not true 

以上例子中$x和$y的值并不等。解決辦法是用round()函數,如:

var_dump(round($x, 2) == round($y, 2)); // this is true

問題的原因在于$x并不是1.6,而是1.599999.

所以本文開頭的例子改成下面這樣就OK了:

  1. $a = 69.1; 
  2.  
  3. $b = $a*100; 
  4.  
  5. $c = round($b)-6910; 

或者使用number_format((float)$a, 2)格式化。

再看一個關于PHP浮點數算出來結果不符合預期的例子。

  1. $a = intval( 0.58*100 ); 
  2.  
  3. $b = 0.58*100; 

$a的值出乎意料的是57,$b的值是58.

解決辦法是:

$a = intval( (0.58*1000)/10 );

或者使用Binary Calculator,即BCMath擴展解決以上問題

補充:

  1. <?php 
  2.     $f = 0.58; 
  3.     var_dump(intval($f * 100)); //為啥輸出57 
  4. ?> 

為啥輸出是57啊? PHP的bug么?

我相信有很多的同學有過這樣的疑問, 因為光問我類似問題的人就很多, 更不用說bugs.php.net上經常有人問…

要搞明白這個原因, 首先我們要知道浮點數的表示(IEEE 754):

浮點數, 以64位的長度(雙精度)為例, 會采用1位符號位(E), 11指數位(Q), 52位尾數(M)表示(一共64位).

符號位:最高位表示數據的正負,0表示正數,1表示負數。

指數位:表示數據以2為底的冪,指數采用偏移碼表示

尾數:表示數據小數點后的有效數字.

這里的關鍵點就在于, 小數在二進制的表示, 關于小數如何用二進制表示, 大家可以百度一下, 我這里就不再贅述, 我們關鍵的要了解, 0.58 對于二進制表示來說, 是無限長的值(下面的數字省掉了隱含的1)..

0.58的二進制表示基本上(52位)是: 0010100011110101110000101000111101011100001010001111

0.57的二進制表示基本上(52位)是: 0010001111010111000010100011110101110000101000111101

而兩者的二進制, 如果只是通過這52位計算的話,分別是:

0.58 -> 0.57999999999999996

0.57 -> 0.56999999999999995

至于0.58 * 100的具體浮點數乘法, 我們不考慮那么細, 有興趣的可以看(Floating point), 我們就模糊的以心算來看… 0.58 * 100 = 57.999999999

那你intval一下, 自然就是57了….

可見, 這個問題的關鍵點就是: “你看似有窮的小數, 在計算機的二進制表示里卻是無窮的”

so, 不要再以為這是PHP的bug了, 這就是這樣的…..

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 美姑县| 海城市| 永寿县| 西昌市| 晋宁县| 定南县| 兴国县| 金门县| 湖州市| 广饶县| 滨州市| 威海市| 额济纳旗| 无锡市| 扬中市| 东光县| 紫阳县| 遂宁市| 上思县| 临海市| 长白| 郧西县| 两当县| 乡宁县| 称多县| 临西县| 宝应县| 鄂尔多斯市| 泽普县| 韶关市| 柘荣县| 怀远县| 丹棱县| 保康县| 乌兰察布市| 祁连县| 锡林浩特市| 仪征市| 肇庆市| 六盘水市| 巨鹿县|