php高精度數計算

2021-10-16 23:13:46 字數 2024 閱讀 6096

一、前方有坑

php在使用加減乘除等運算子計算浮點數的時候,經常會出現意想不到的結果,特別是關於財務資料方面的計算,給不少工程師惹了很多的麻煩。比如今天工作終於到的乙個案例:

$a = 2586;

$b = 2585.98;

var_dump(a−a-

a−b);期望的結果是:float(0.02)

實際結果:

float(0.019999999999982)

人生有坑,處處提防

二、防坑攻略:

1、通過乘100的方式轉化為整數加減,然後在除以100轉化回來……

2、使用number_format轉化成字串,然後在使用(float)強轉回來……

3、php提供了高精度計算的函式庫,實際上就是為了解決這個浮點數計算問題而生的。

主要函式有:

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

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

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

bcmod — 求高精度數字餘數

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

bcpow — 求高精度數字乘方

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

bcscale — 配置預設小數點位數,相當於就是linux bc中的」scale=」

bcsqrt — 求高精度數字平方根

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

前兩種流氓的辦法就不測試了,使用bcsub測試第三種兩數相減的例子,

先看bcsub用法(來自官網)

string bcsub ( string $left_operand , string $right_operand [, int $scale = int ] )

引數left_operand 字串型別的左運算元.

right_operand 字串型別的右運算元.

scale 此可選引數用於設定結果中小數點後的小數字數。也可通過使用 bcscale() 來設定全域性預設的小數字數,用於所有函式。

返回值 返回減法之後結果為字串型別.

測試**:

var_dump(bcsub(a,a,

a,b,2));

結果0.02

三、為啥有坑:

php的bug?不是,這是所有語言基本上都會遇到的問題,所以基本上大部分語言都提供了精準計算的類庫或函式庫。

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

浮點數, 以64位的長度(雙精度)為例, 會採用1位符號位(e), 11指數字(q), 52位尾數(m)表示(一共64位).

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

指數字:表示資料以2為底的冪,指數採用偏移碼表示

尾數:表示資料小數點後的有效數字.

這裡的關鍵點就在於, 小數在二進位制的表示, 小數如何轉化為二進位制呢?

演算法是乘以2直到沒有了小數為止。這裡舉個例子,0.9表示成二進位制數

0.9*2=1.8 取整數部分 1

0.8(1.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.6*2=1.2 取整數部分 0

0.9二進位制表示為(從上往下): 1100100100100…

注意:上面的計算過程迴圈了,也就是說*2永遠不可能消滅小數部分,這樣演算法將無限下去。很顯然,小數的二進位制表示有時是不可能精確的 。其實道理很簡單,十進位制系統中能不能準確表示出1/3呢?同樣二進位制系統也無法準確表示1/10。這也就解釋了為什麼浮點型減法出現了"減不盡"的精度丟失問題。

換句話說:我們看到十進位制小數,在計算機內儲存的不是乙個精確的數字,也不可能精確。所以在數字加減乘除後出現意想不到的結果。

四、防坑提示

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

php高精度數值計算

bcadd 將兩個高精度數字相加 bccomp 比較兩個高精度數字,返回 1,0,1 bcdiv 將兩個高精度數字相除 bcmod 求高精度數字餘數 bcmul 將兩個高精度數字相乘 bcpow 求高精度數字乘方 bcpowmod 求高精度數字乘方求模,數論裡非常常用 bcscale 配置預設小數點...

高精度 數樓梯

洛谷 p1255 數樓梯 題目描述 樓梯有n階,上樓可以一步上一階,也可以一步上二階。編乙個程式,計算共有多少種不同的走法。分析 只用稍微用用腦子就可以看出,這是一道斐波那契數列的問題 不過省略了開頭的1,即這裡的數列為 12358 注意n 0,1,2的情況。然而這題需要高精所以寫的特別長 incl...

高精度 數樓梯

題目 樓梯有n階,上樓可以一步上一階,也可以一步上二階。編乙個程式,計算共有多少種不同的走法。乙個數字,樓梯數。走的方式幾種。輸入 1 複製 4輸出 1 複製 5說明 提示 60 n 50 100 n 5000 原本一看,這不是 斐波那契數列 嗎,直接公式下去寫完,dp i dp i 1 dp i ...