PHP浮點數精度問題

更新 發佈閱讀 4 分鐘

先前在處理公司額度計算的開發時,遇到了PHP浮點數的資料處理會出現精度丟失的問題,還好google發現大家都有碰過這個坑?

根據PHP官方說明,浮點數的精度有限。儘管取決於系統,PHP 通常使用 IEEE 754 雙精度格式,則由於取整而導致的最大相對誤差為 1.11e-16。非基本數學運算可能會給出更大誤差,並且要考慮到進行複合運算時的誤差傳遞。此外,以十進制能夠精確表示的有理數如 0.1 或 0.7,無論有多少尾數都不能被內部所使用的二進制精確表示,因此不能在不丟失一點點精度的情況下轉換為二進制的格式。這就會造成混亂的結果:例如,floor((0.1+0.7)*10) 通常會返回 7 而不是預期中的 8,因為該結果內部的表示其實是類似 7.9999999999999991118...。

範例參考:

首先先將浮點數轉換為二進制,並透過兩數二進制加總,並轉回十進制即可得出精度丟失的結果

//浮點數 2.4 轉為二進制
2.4 = 10.011001100110011001100110011001100110011001100110011;

0.8 = 0.1100110011001100110011001100110011001100110011001101;

// 2.4 的二進制與 0.8 的二進制結果加總
10.011001100110011001100110011001100110011001100110011
+ 0.1100110011001100110011001100110011001100110011001101;
--------------------------------------------------------------------------------
11.0011001100110011001100110011001100110011001100110011
//將計算結果 11.0011001100110011001100110011001100110011001100110011
//轉為十進制
11.0011001100110011001100110011001100110011001100110011 = 3.19999999999999996

根據上述計算,我們可以看出來在電腦執行後十進制為3.19999999999999996 而非我們認為的2.4+0.8=3.2,電腦對於浮點數的處理,通過轉為二進制運算後,在轉換為十進制,就會造成精度丟失的問題。

而根據PHP處理浮點數造成精度丟失的問題,可以解決的辦法大概就是先小數轉為整數去計算,最後在對運算結果進行計算後再轉回小數,但還好大多數人都踩過這個坑,而PHP官方也針對這個問題提供了高精度計算的函數庫,就是為了解決這個問題的處理,而目前使用Laravel框架就有支持囉,直接函數處理計算

bcadd — 將兩個高精度數字相加

bccomp — 比較兩個高精度數字,返回-1, 0, 1

bcdiv — 將兩個高精度數字相除

bcmod — 求高精度數字餘數

bcmul — 將兩個高精度數字相乘

bcpow — 求高精度數字乘方

bcpowmod — 求高精度數字乘方求模,數論裡非常常用

bcscale — 配置默認小數點位數,相當於就是Linux bc中的”scale=

bcsqrt — 求高精度數字平方根

bcsub — 將兩個高精度數字相減

註:根據官網說明文件以bcadd 函數為例,我們可以看到,這邊作為兩個數字的加總,我們必須使用的是字串類型的格式,故在執行高精度數字運算加總時,要先將取得金額數字轉成string的格式後,在使用bacdd進行兩個數字的相加處理

raw-image
//float to string
$amount = number_format($amount, 4, '.', '');

bcadd($num1, $amount, 4)

總結:還好小菜雞撰寫的功能在dev交由測試的時候,測試人員努力測爆時有發現尾數加減的問題,因為我也是第一次遇到,算是一個難得的經驗累積,特此紀錄~供大家參考~

參考

https://www.php.net/manual/zh/language.types.float.php

https://www.php.net/manual/zh/book.bc.php


留言
avatar-img
DDDDD的沙龍
15會員
37內容數
學涯無止境,透過每日or每週模仿學習筆記,不管是哪些領域也好,總有一天也可以從菜雞變小雞
DDDDD的沙龍的其他內容
2023/12/13
待業中後,發現時間變很多就開始東看看西看看,思考著要如何更深入理解Laravel框架的運用,而在Laravel框架中哪些部分是框架替我們做了哪些處理,推薦一個影片給大家一起學習理解。
Thumbnail
2023/12/13
待業中後,發現時間變很多就開始東看看西看看,思考著要如何更深入理解Laravel框架的運用,而在Laravel框架中哪些部分是框架替我們做了哪些處理,推薦一個影片給大家一起學習理解。
Thumbnail
2023/12/09
現在AI工具太多,且框架對於資安支援及處理也越來越方便,反而開始會容易忽略最底層的知識,這邊回顧MySQL的鎖,順便記錄一下找到的一些影片資源,並整理筆記
Thumbnail
2023/12/09
現在AI工具太多,且框架對於資安支援及處理也越來越方便,反而開始會容易忽略最底層的知識,這邊回顧MySQL的鎖,順便記錄一下找到的一些影片資源,並整理筆記
Thumbnail
2023/12/05
這邊主要是遇到功能需要處理時區,雖然主管給的筆記已經寫得很完美了,但覺得還是得理解吸收後並記錄自己的筆記後,好像才能有效吸收到腦袋裡
Thumbnail
2023/12/05
這邊主要是遇到功能需要處理時區,雖然主管給的筆記已經寫得很完美了,但覺得還是得理解吸收後並記錄自己的筆記後,好像才能有效吸收到腦袋裡
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
市場經驗拉長之後,很多投資人都會遇到同一個問題:不是方向看錯,而是部位太集中個股,常常跟大趨勢脫節。 早年的台股環境,中小股非常吃香,反而權值股不動,但QE量化寬鬆後,特別是疫情之後,後疫情時代,鈔票大量在股市走動,這些大資金只能往權值股走,因此早年小P的策略偏向中小型個股,但近年AI興起,高技術
Thumbnail
市場經驗拉長之後,很多投資人都會遇到同一個問題:不是方向看錯,而是部位太集中個股,常常跟大趨勢脫節。 早年的台股環境,中小股非常吃香,反而權值股不動,但QE量化寬鬆後,特別是疫情之後,後疫情時代,鈔票大量在股市走動,這些大資金只能往權值股走,因此早年小P的策略偏向中小型個股,但近年AI興起,高技術
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
昨日补分
Thumbnail
昨日补分
Thumbnail
在知道平均數與標準差之後,就可以進一步了解什麼是所謂的「標準分數」了。 標準分數的重要用途是可以幫助我們比較不同單位、不同分散程度的數值。 以概念來說,跟百分等級(PR)有點類似的味道吧。 標準分數在後續的統計當中也很常會出現的。
Thumbnail
在知道平均數與標準差之後,就可以進一步了解什麼是所謂的「標準分數」了。 標準分數的重要用途是可以幫助我們比較不同單位、不同分散程度的數值。 以概念來說,跟百分等級(PR)有點類似的味道吧。 標準分數在後續的統計當中也很常會出現的。
Thumbnail
根據PHP官方說明,浮點數的精度有限。儘管取決於系統,PHP 通常使用 IEEE 754 雙精度格式,則由於取整而導致的最大相對誤差為 1.11e-16。非基本數學運算可能會給出更大誤差,並且要考慮到進行複合運算時的誤差傳遞。
Thumbnail
根據PHP官方說明,浮點數的精度有限。儘管取決於系統,PHP 通常使用 IEEE 754 雙精度格式,則由於取整而導致的最大相對誤差為 1.11e-16。非基本數學運算可能會給出更大誤差,並且要考慮到進行複合運算時的誤差傳遞。
Thumbnail
前言 這是紀錄本人學習Unity C#時的筆記,希望讓自己能夠整理思緒,方便記憶。 因為是新手自學的關係,也很有可能有誤解或錯誤的地方,請見諒… 變數 宣告變數不能使用數字開頭,或是除了_之外的符號。 ·整數 int ·浮點數 float、double float 精度低、佔的資源較少,double
Thumbnail
前言 這是紀錄本人學習Unity C#時的筆記,希望讓自己能夠整理思緒,方便記憶。 因為是新手自學的關係,也很有可能有誤解或錯誤的地方,請見諒… 變數 宣告變數不能使用數字開頭,或是除了_之外的符號。 ·整數 int ·浮點數 float、double float 精度低、佔的資源較少,double
Thumbnail
一、自動轉型-二、明確轉型-三、Parse方法-補充、日期時間的轉換>>> 當我們在撰寫程式過程中,有可能會遇到在做資料處理時與一開始宣告的資料型別不一樣,這時就會需要資料型別轉換了。那這邊有四種轉換介紹: 一、自動轉型 運算過程中在精確度不會改變時,程式就會自動幫我們做轉型處理,什麼意思呢?就是
Thumbnail
一、自動轉型-二、明確轉型-三、Parse方法-補充、日期時間的轉換>>> 當我們在撰寫程式過程中,有可能會遇到在做資料處理時與一開始宣告的資料型別不一樣,這時就會需要資料型別轉換了。那這邊有四種轉換介紹: 一、自動轉型 運算過程中在精確度不會改變時,程式就會自動幫我們做轉型處理,什麼意思呢?就是
Thumbnail
分類 △單精度浮點數、單精度浮點值(float) △雙精度浮點數、雙精度浮點值(double) △長雙精度浮點數、長雙精度浮點值(long double) 有效位數是什麼? 儲存形式 不精確的原因 範圍與有效位數的差別 浮點數不被建議使用的原因 精確問題 速度問題 結論
Thumbnail
分類 △單精度浮點數、單精度浮點值(float) △雙精度浮點數、雙精度浮點值(double) △長雙精度浮點數、長雙精度浮點值(long double) 有效位數是什麼? 儲存形式 不精確的原因 範圍與有效位數的差別 浮點數不被建議使用的原因 精確問題 速度問題 結論
Thumbnail
說明 重點 △定義變數 △文字的定義 △文字與數字的差別 △整數與浮點數 △signed(有號)與unsigned(無號)的區別 △e是什麼符號? 分類 △字元 △字串 △短整數 △整數 △長整數 △超長整數 △單精度浮點數 △雙精度浮點數 △長雙精度浮點數 應用 宣告與輸出 運算符 結論
Thumbnail
說明 重點 △定義變數 △文字的定義 △文字與數字的差別 △整數與浮點數 △signed(有號)與unsigned(無號)的區別 △e是什麼符號? 分類 △字元 △字串 △短整數 △整數 △長整數 △超長整數 △單精度浮點數 △雙精度浮點數 △長雙精度浮點數 應用 宣告與輸出 運算符 結論
Thumbnail
何謂浮點數? 在了解浮點數之前,可以先大概了解一下跟他相對應的定點數 定點數: 小數點固定,整個數字表示為 整數 + 小數 今天要表示 25.125 那定點數表示法就是 25 125,中間再以小數點作為連接 浮點數: 小數點是漂浮不定的,整個數字表示分為 有效數字跟指數,類似於科學記號表示法 今天要
Thumbnail
何謂浮點數? 在了解浮點數之前,可以先大概了解一下跟他相對應的定點數 定點數: 小數點固定,整個數字表示為 整數 + 小數 今天要表示 25.125 那定點數表示法就是 25 125,中間再以小數點作為連接 浮點數: 小數點是漂浮不定的,整個數字表示分為 有效數字跟指數,類似於科學記號表示法 今天要
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News