• 技术文章 >后端开发 >php教程

    php中小数精度的代码解析

    不言不言2018-08-04 14:02:41原创925
    本篇文章给大家带来的内容是关于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位)是: 0010100011110101110000101000111101011100001010001111

    0.57的二进制表示基本上(52位)是: 001000111101011100001010001111010111000010100011110

    而两者的二进制, 如果只是通过这52位计算的话,分别是:

       0.58 --> 0.57999999999999996

    0.57 --> 0.5699999999999999

    所以,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 函数

    建议使用高精度函数:

    高精度函数

    使用高精度函数实现四舍五入:

        function getBcRound($number, $precision = 0)
        {
            $precision = ($precision < 0)
                       ? 0
                       : (int) $precision;
            if (strcmp(bcadd($number, '0', $precision), bcadd($number, '0', $precision+1)) == 0) {
                return bcadd($number, '0', $precision);
            }
            if (getBcPresion($number) - $precision > 1) {
                $number = getBcRound($number, $precision + 1);
            }
            $t = '0.' . str_repeat('0', $precision) . '5';
            return $number < 0
                   ? bcsub($number, $t, $precision)
                   : bcadd($number, $t, $precision);
        }
        
        function getBcPresion($number) {
            $dotPosition = strpos($number, '.');
            if ($dotPosition === false) {
                return 0;
            }
            return strlen($number) - strpos($number, '.') - 1;
        }
        
        $money = getBcRound(0.99, 2);

    相关文章推荐:

    PHP中AES加密文件的解析(附代码)

    php的curl中post方式和get方式的请求代码

    关于PHP中间键的内容解析

    以上就是php中小数精度的代码解析的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:php中小数精度
    上一篇:PHP中AES加密文件的解析(附代码) 下一篇:Thinkphp批量下载图片和文件件的代码实例
    千万级数据并发解决方案

    相关文章推荐

    • 用PHP实现自己的sha-256哈希算法!• 怎么采用新窗口打开• DEDECMS分页标签的有关问题,用求大神• php上传文件有关问题• php字符串转化成数组解决思路
    1/1

    PHP中文网