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
15會員
37內容數
學涯無止境,透過每日or每週模仿學習筆記,不管是哪些領域也好,總有一天也可以從菜雞變小雞
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
你可能也想看
Google News 追蹤
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
1. 什麼是浮點數? 浮點數是一種用來表示小數或非常大的數字的方法。 它的作用是讓電腦能夠處理像 3.14159(圓周率)或 1234567890(很大的數字)這樣的數字。 為什麼要有浮點數? 👉 因為用電腦表示這些數字的時候,記憶體有限,直接儲存會很浪費空間,效率也低。 2.
Thumbnail
FP8 精度是一種浮點數表示格式,代表了 8-bit 浮點數。它是最新引入的數值精度形式,主要用於深度學習中的 AI 訓練和推論,旨在在性能與數據精度之間取得更好的平衡。 1. FP8 精度的基本概念 浮點數表示格式: 浮點數是一種數據表示方式,分為 符號位、指數位 和 尾數位。FP8 格式的
Thumbnail
題目敘述 Integer to English Words 給定一個整數num 請轉換成對應的的英文數字表達(One, Two, Three, ... 那種數字表達式)
Thumbnail
我們在上一篇簡單介紹了 int(整數)是做什麼用的,接下來要介紹常和他一起出現的好朋友 float 浮點數 跟 str 字串。 float 浮點數: 函數的式子寫做 float( ) ,浮點數就是帶有小數點的資料型別,他可以將字串或是數字轉換為有小數點的狀態。前提是字串內的字符必須是數字的格
Thumbnail
題目要求計算兩個二進位字串的相加,並以字串的形式輸出。 字串內容只包含'0'或'1'字元。 複雜度分析 時間複雜度為O(m+n),空間複雜度為O(m+n)。
Thumbnail
本章節介紹了PHP中的各種運算符,包括算數運算子、比較運算子、賦值運算子和位元運算子。還討論了運算子的優先等級及其在表達式中的應用。了解這些運算符及其優先等級可以幫助編寫更高效和準確的PHP代碼。
Thumbnail
這一章節介紹了PHP的各種資料型別,包括內建型別如整數、浮點數、布爾值、字符串、數組、對象、空值和資源,並解釋了型別轉換的方式。此外,還討論了自訂型別、元組型別、集合型別、陣列型別和字典型別的實現方法。
有時候在使用數學運算時,會出現一些看似反直覺的結果。 這些錯誤可能是由於我們對於數學規則的誤解或者忽略了一些細節所導致的。 以下是一些 Python 的例子: 除餘數 例如負數求餘數。 假設-15 % 90 狀況下 會下意思覺得結果還是 -15 但輸出的結果是 75。
Thumbnail
「在 JavaScript 中 0.1 + 02 等於多少?」 這是我在面試時會問的一題。有經驗的工程師應該知道我在問什麼,但相信仍有不少人可能還不知道 0.1 + 0.2 不等於 0.3。
Thumbnail
該文章介紹了浮點數精度的概念,包括雙精度、單精度、半精度、8位精度、4位精度、量化精度、多精度和混合精度。同時還介紹了nVidia A100開始的TF32精度和BF16格式,並提供了相關的數據對比。文章強調了TF32和BF16的潛在應用價值及特點。
Thumbnail
徵的就是你 🫵 超ㄅㄧㄤˋ 獎品搭配超瞎趴的四大主題,等你踹共啦!還有機會獲得經典的「偉士牌樂高」喔!馬上來參加本次的活動吧!
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
1. 什麼是浮點數? 浮點數是一種用來表示小數或非常大的數字的方法。 它的作用是讓電腦能夠處理像 3.14159(圓周率)或 1234567890(很大的數字)這樣的數字。 為什麼要有浮點數? 👉 因為用電腦表示這些數字的時候,記憶體有限,直接儲存會很浪費空間,效率也低。 2.
Thumbnail
FP8 精度是一種浮點數表示格式,代表了 8-bit 浮點數。它是最新引入的數值精度形式,主要用於深度學習中的 AI 訓練和推論,旨在在性能與數據精度之間取得更好的平衡。 1. FP8 精度的基本概念 浮點數表示格式: 浮點數是一種數據表示方式,分為 符號位、指數位 和 尾數位。FP8 格式的
Thumbnail
題目敘述 Integer to English Words 給定一個整數num 請轉換成對應的的英文數字表達(One, Two, Three, ... 那種數字表達式)
Thumbnail
我們在上一篇簡單介紹了 int(整數)是做什麼用的,接下來要介紹常和他一起出現的好朋友 float 浮點數 跟 str 字串。 float 浮點數: 函數的式子寫做 float( ) ,浮點數就是帶有小數點的資料型別,他可以將字串或是數字轉換為有小數點的狀態。前提是字串內的字符必須是數字的格
Thumbnail
題目要求計算兩個二進位字串的相加,並以字串的形式輸出。 字串內容只包含'0'或'1'字元。 複雜度分析 時間複雜度為O(m+n),空間複雜度為O(m+n)。
Thumbnail
本章節介紹了PHP中的各種運算符,包括算數運算子、比較運算子、賦值運算子和位元運算子。還討論了運算子的優先等級及其在表達式中的應用。了解這些運算符及其優先等級可以幫助編寫更高效和準確的PHP代碼。
Thumbnail
這一章節介紹了PHP的各種資料型別,包括內建型別如整數、浮點數、布爾值、字符串、數組、對象、空值和資源,並解釋了型別轉換的方式。此外,還討論了自訂型別、元組型別、集合型別、陣列型別和字典型別的實現方法。
有時候在使用數學運算時,會出現一些看似反直覺的結果。 這些錯誤可能是由於我們對於數學規則的誤解或者忽略了一些細節所導致的。 以下是一些 Python 的例子: 除餘數 例如負數求餘數。 假設-15 % 90 狀況下 會下意思覺得結果還是 -15 但輸出的結果是 75。
Thumbnail
「在 JavaScript 中 0.1 + 02 等於多少?」 這是我在面試時會問的一題。有經驗的工程師應該知道我在問什麼,但相信仍有不少人可能還不知道 0.1 + 0.2 不等於 0.3。
Thumbnail
該文章介紹了浮點數精度的概念,包括雙精度、單精度、半精度、8位精度、4位精度、量化精度、多精度和混合精度。同時還介紹了nVidia A100開始的TF32精度和BF16格式,並提供了相關的數據對比。文章強調了TF32和BF16的潛在應用價值及特點。