php中小數精度的程式碼解析

不言
發布: 2023-04-03 15:44:02
原創
2002 人瀏覽過

這篇文章帶給大家的內容是關於php中小數精度的程式碼解析,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

專案中保留兩位小數四捨五入遇到精確度問題:

$num = 0.99;
$num1 = round($num, 2);//0.98999999999999999
$num2 = floatval($num);//0.98999999999999999
登入後複製

目前解:

sprintf("%.2f", round($money, 2));//会自动四舍五入
echo substr(sprintf("%.3f",$n), 0, -1);//不四舍五入
登入後複製

測試結果:

var_dump(json_encode(round(0.99 ,2)));//0.98999999999999999
var_dump(round(0.99 ,2));//0.99

$f = 0.58;    
var_dump(intval($f * 100));//57
登入後複製

關於等於57這個問題,我們可以分析一下:

浮點數的表示(IEEE 754:IEEE二進位浮點數算術標準):

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

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

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

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

     0.58 對於二進位表示來說, 是無限長的值:

  0.58的二進位表示基本上(52位)是: 001010001111010111000010100011110101110000101000111000111101011100001010001111 001000111101011100001010001111010111000010100011110

     而兩者的二進位, 如果只是透過這52位元計算出來的話,分別是:

      0.58 --> 0.57999999999999996

#Too; 0.57999999999999996

> 99

          所以,0.58 * 100 結果會:57.999999999,轉成整數:57

關於浮點數的二進位表示可以參考:浮點數的二進位表示

##類似:##
(0.1 + 0.7) == 0.8//false

floor((0.1+0.7)*10)//7 
//内部结果可能是:7.9999999999
//所以:不可能精确的用有限位数表达某些十进制分数
1/3=3.33333333333
//而3.333333333333333*3,却不是1
登入後複製
##所以結論:

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

建議使用高精度函數:

高精度函數

#bcadd — 2個任意精確度數字的加法計算
  • #bccomp — 比較兩個任意精確度的數字
  • bcp — 2個任意精確度的數字除法計算

  • bcmod — 對一個任意精確度數字取模

  • #bcmul — 2個任意精確度數字乘法計算
  • #bcpow — 任意精確度數字的乘方
  • bcpowmod — Raise an arbitrary precision number to another, reduced by a specified modulus
  • bcscale — 設定所有bc數學函數的預設小數點保留位數
  • bcsqrt — 任意精確度數字的二次方根

  • bcsub — 2個任意精確度數字的減法

  • #使用高精度函數實現四捨五入:

        function getBcRound($number, $precision = 0)
        {
            $precision = ($precision < 0)
                       ? 0
                       : (int) $precision;
            if (strcmp(bcadd($number, &#39;0&#39;, $precision), bcadd($number, &#39;0&#39;, $precision+1)) == 0) {
                return bcadd($number, &#39;0&#39;, $precision);
            }
            if (getBcPresion($number) - $precision > 1) {
                $number = getBcRound($number, $precision + 1);
            }
            $t = &#39;0.&#39; . str_repeat(&#39;0&#39;, $precision) . &#39;5&#39;;
            return $number < 0
                   ? bcsub($number, $t, $precision)
                   : bcadd($number, $t, $precision);
        }
        
        function getBcPresion($number) {
            $dotPosition = strpos($number, &#39;.&#39;);
            if ($dotPosition === false) {
                return 0;
            }
            return strlen($number) - strpos($number, &#39;.&#39;) - 1;
        }
        
        $money = getBcRound(0.99, 2);
    登入後複製
     相關文章推薦:

    PHP中AES加密檔案的解析(附程式碼)

    #php的curl中post方式與get方式的請求程式碼

    關於PHP中間鍵的內容解析

    以上是php中小數精度的程式碼解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板