php高精度计算的封装介绍

本文介绍了PHP中浮点数精度丢失的问题,以及如何通过bcMath扩展进行高精度计算。bcMath库提供了一系列函数如bcadd、bcsub等,用于解决浮点数运算的不精确性。文章还讨论了舍入和四舍五入的策略,并给出了封装bcMath函数的示例代码,以实现更人性化的数学操作。

概要

php浮点数精度计算的坑
$a = 2586;
$b = 2585.98;
var_dump($a-$b);

期望的结果是:float(0.02)
实际结果:
float(0.019999999999982)
原因
小数的二进制表示有时是不可能精确的。
其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。
这也就解释了为什么浮点型减法出现了"减不尽"的精度丢失问题。

方案

1、通过乘100的方式转化为整数加减,然后在除以100转化回来……
2、使用number_format转化成字符串,然后在使用(float)强转回来……
3、php提供了高精度计算的函数库,实际上就是为了解决这个浮点数计算问题而生的。

php提供的高精度函数库bc

1.运行条件
    运行bcsub函数需要 php-bcmath的扩展。(一般来说,在7版本以后都已经是自带的了)
2.

BC的主要相关函数

bcadd — 将两个高精度数字相加
bccomp — 比较两个高精度数字,返回-1, 0, 1
bcdiv — 将两个高精度数字相除
bcmod — 求高精度数字余数
bcmul — 将两个高精度数字相乘
bcpow — 求高精度数字乘方
bcpowmod — 求高精度数字乘方求模,数论里非常常用
bcscale — 配置默认小数点位数,相当于就是Linux bc中的”scale=”
bcsqrt — 求高精度数字平方根
bcsub — 将两个高精度数字相减

可能为缺陷

1.直接截取的数字
2.不遵循四舍五入原则
3.返回值类型是字符串

为何需要封装?

当然是因为上面的缺陷啦
当然也是为了更人性化的使用

代码示例

示例
//只能实现基本的加减乘除
if (!function_exists('hlg_math')) {
    /**
     * 高精度数字计算封装
     * @param int $left
     * @param string $symbol
     * @param int $right
     * @param int $default
     * @return string|null
     * @author: baiwei
     * @Time: 2020/7/17 0012 10:51
     */
    function hlg_math($left = 0, $symbol = '+', $right = 0, $default = 2)
    {
        //设置全局保留的位数
        bcscale($default);

        switch ($symbol) {
            case '+':
                $res = bcadd(floatval($left), floatval($right));
                break;
            case '-':
                $res = bcsub(floatval($left), floatval($right));
                break;
            case '*':
                $res = bcmul(floatval($left), floatval($right));
                break;
            case '/':
                $res = bcdiv(floatval($left), floatval($right));
                break;
            case '%':
                $res = bcmod(floatval($left), floatval($right));
                break;
            default:
                $res = 0;
                break;
        }
        // 直接返回浮点类型
        return floatval($res);
    }
}

关于舍去以及四舍五入

1.鲁迅曾经说过:对于浮点数的计算没有绝对的精确
2.谁说的舍去就一定是缺陷?
    在遵照鲁迅名言的情况下,没有绝对的精准时,舍去保留若干位和四舍五入保留若干位其实都为等阶的不准确
    例如:
    1.  如果是卖家对用户发放金额的情况下
        是不是卖家会更倾向于舍去算法?
        因为毕竟是舍去,这*至少不亏
        
    2.  如果是需要配合微信支付的相关手续费接口
        微信手续费的计算甚至于有千分之六的概念,
        那么就一定浮点数会超过3位,
        他们采用的就是四舍五入的方式保留了2位

如果要BC支持四舍五入

在设置全局保留N位的情况下隐式保留N+1位,然后对参数进行round四舍五入保留N位置即可解决不能四舍五入的难点

关于封装

一般来说计算都需要三个参数,左右数以及运算符,这里看看大家有没有更好的封装建议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值