• <menu id="imq0s"><strong id="imq0s"></strong></menu>
  • 福州網站建設>網站新聞>php技術

    踩坑之json_encode精度丟失問題

    發布日期:2022-01-12瀏覽次數:223 來源:福州網站建設

    1.前言
    最近在工作中,后臺出現了這樣的錯誤,傳遞的手續費是29塊錢,但是傳遞到了第三方接口就報錯了,查看日志顯示該手續費變成了28.999999999999996,日志如下:






    明明是29怎么就變了?通過斷點檢測,原來是json_encode()轉換的問題


    2.案例演示
    $param={


    ‘amount’=>5000,


    ‘fee’=>29


    }


    var_dump(json_encode($param));//{"amount":5000,"fee":28.999999999999999999996}
    3.解決方法
    3.1方法1:強行轉換成字符串保證精度
    $request['param']['feeAmount']=(string)$request['param']['feeAmount'];


    注意:使用這種方法千萬要注意,對接接口是否有變量類型要求


    3.2方法2:格式化數字number_format函數
    number_format(number,decimals,decimalpoint,separator)


    參數:


    number參數是要格式化的數據
    decimals參數是保留的小數
    decimalpoint參數是規定用作小數點的字符串
    separator參數是規定用作千位分隔符的字符串
    案例:
    $request['param']['feeAmount']=(int)number_format($request['param']['feeAmount'],0);


    注意:number_format返回的是字符串string,要注意接口是否有規范要求,如果有,則須強行轉換為int或接口規范的類型


    疑問1:這時候應該有人在想能不能直接強制轉換為int呢?注意,float強制轉換成int有坑!


    答:int類型是向下取整的,比如:12910.9 會被轉換為 12910


    疑問2:這時就會有人問我,浮點數顯示的是8,為什么轉換成整數會變成7?


    答:floor((0.1+0.7)*10),其結果是7而不是8,是因為該結果內部表示的是7.9999.....所以不要相信浮點數結果精確,也不要比較兩個浮點數是否相等
    3.3方法3:修改配置項serialize_precision
    json_encode() 轉換浮點小數溢出現象只出現在PHP 7.1+版本,是因為php源碼對于json_encode()轉換使用到了serialize_precision配置項,如下圖


    static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */
    {
        size_t len;
        char num[PHP_DOUBLE_MAX_LENGTH];
        php_gcvt(d, (int)PG(serialize_precision), '.', 'e', num);
        len = strlen(num);
        if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_DOUBLE_MAX_LENGTH - 2) {
            num[len++] = '.';
            num[len++] = '0';
            num[len] = '\0';
        }
        smart_str_appendl(buf, num, len);
    }
    關于PHP函數serialize_precision (integer)的一些概念了解:


    適用范圍:PHP_INI_ALL;


    默認值:100


    serialize_precision指令的數量決定了雙打和彩車被序列化后的浮點數字存儲。設置到一個合適的值,確保精度的數字時,可能丟失以后反序列化。所以我們要使得json_encode()轉換浮點數沒有小數溢出,建議使用默認值 serialize_precision = -1 即可 。


    3.4知識點補充
    json_encode有個選項JSON_PRESERVE_ZERO_FRACTION,表示如果是個整數, 是否保留小數點和尾數0,舉例如下:


    <?php
    echo json_encode(223.0);// 223
    echo json_encode(223.0, JSON_PRESERVE_ZERO_FRACTION);// 223.0
    3.5其他取整函數
    四舍五入取整 round(param)
    向上取整 ceil(param)
    向下取整 floor(param)


    4.bcsub()函數精度相減
    格式:


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


    說明:


    2個任意精度數字的減法


    參數:


    left_operand:字符串類型的左操作數.


    right_operand:字符串類型的右操作數.


    scale:此可選參數用于設置結果中小數點后的小數位數。也可通過使用 bcscale() 來設置全局默認的小數位數,用于所有函數。


    返回值:


    返回減法之后結果為字符串類型.


    代碼案例:


    <?php
    $a  =  '1.234' ;
    $b  =  '5' ;
    echo  bcsub ( $a ,  $b );      // -3
    echo  bcsub ( $a ,  $b ,  4 );   // -3.7660
    ————————————————
    版權聲明:本文為CSDN博主「拯救世界的派大星」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
    原文鏈接:https://blog.csdn.net/m0_46266407/article/details/105556444

    以上是由福州網站建設的小編為你分享了"踩坑之json_encode精度丟失問題"文章,如果你在這方面有什么問題,隨時聯系我們

    php技術有關的文章
    如果您有什么問題,歡迎咨詢我們客服! 點擊QQ咨詢
    色妞网AV天堂,特级毛片高清特级毛片,免费欧洲毛片A级喷水视频软件
  • <menu id="imq0s"><strong id="imq0s"></strong></menu>