PHP中小數計算的問題

前言

今天在開發過程中碰到一個浮點數計算的精度問題,事實上也不是第一次見到這種情況了,之前也碰到過好幾次,但是由於時間原因,知識按照網上說的方法解決掉了這個問題,並沒有深究其中原理,等到不忙的時候也忘了這回事了,今天剛好有時間,來研究一下這個問題,以下內容是我自己在網上看過幾篇相關博文再加上自己的理解寫出來的,如果有錯誤煩請指正

問題

假設有如下代碼塊,大家猜想一下會輸出什麼,這裏正確結果應該是 0.1 對吧,但是這裏卻輸出的是 0.099999999999909,起初看到這個結果我也很匪夷所思,不急,下面我來說下原理

$a = 2000;
$b = 1999.9;
$c = $a-$b;
// 0.099999999999909
echo $c;

解析

一、計算機是如何存儲小數的
推薦大家看下浮點數(floating-point number)二進制存儲格式,這篇文章講得很詳細
二、造成浮點數計算精度偏差的原因
這裏我們用上面的例子來說明:

已知 2000-1999.9 = 0.1

十進制0.1 轉爲二進制(乘2取整法)

0.1 * 2 = 0.2 整數位: 0
0.2 * 2 = 0.4 整數位: 0
0.4 * 2 = 0.8 整數位: 0
0.8 * 2 = 1.6 整數位: 1
0.6 * 2 = 1.2 整數位: 1
0.2 * 2 = 0.4 整數位: 0
0.4 * 2 = 0.8 整數位: 0
0.8 * 2 = 1.6 整數位: 1


這裏大家可以看到已經成了死循環,始終無法讓小數部分成爲0,所以後面會有無限個0011,但是計算機存儲浮點數的大小是有限的,看過上面那篇文章的同學就會知道,單精度最多32bit,雙精度64bit,但是這裏有無限位,最多也只能保留64位,到這裏大家明白了爲什麼上面的例子會得出 0.099999999999909 這個值了吧,那問題來了,這個問題怎麼解決呢?

解決方案

對於這種問題,我經常用下面這兩種解決方案:

  • 將要計算的小數乘100轉爲整數再進行計算,得到結果後再除100
  • 使用BCmath擴展函數來計算

本篇博文到這裏就結束了,如果對你有幫助的話動個小手給我點個贊吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章