php7.1浮点数运算问题

最近在项目中遇到一个问题,测试服务器接口返回金额精度缺失,导致app解析不正确发生闪退。调试后发现浮点数在json_encode后损失了精度,如下图所示。

输入图片说明

网上说是因为php7.1版本的serialize_precision配置不当导致,但是查看配置文件后发现配置正确,默认值为-1。

在服务器上测试浮点数运算如下:

输入图片说明

测试后发现浮点数的加减运算会导致精度损失。

我们都知道计算机是通过二进制数存储浮点数的一个近似值,浮点数之间的比较和计算难免有误差。

单精度 float 的存储方式如下:

输入图片说明

双精度 double 的存储方式如下:

输入图片说明

php7.1版本可以通过设置serialize_precision和precision两个配置项来指定浮点数精度,但是也不能保证满足项目对于浮点数运算的严格要求。

解决方案是将项目中的金额单位从元(浮点数,保留两位小时)转成分(整型)运算,最后除以100避免了浮点数加减运算导致的精度损失。

示例代码如下:

    /**
     * 元转分
     *
     * @param $amount
     * @return mixed
     */
    public static function yuanToFen($amount)
    {
        return $amount * 100;
    }

    /**
     * 分转元
     *
     * @param $amount
     * @return float
     */
    public static function fenToYuan($amount)
    {
        return $amount / 100;
    }

    /**
     * 元相加运算,不损失精度
     *
     * @param $yuanAmounts
     * @return int
     */
    public static function yuanAdd(...$yuanAmounts)
    {
        $fenAmountTotal = 0;
        foreach ($yuanAmounts as $yuanAmount) {
            $fenAmountTotal += intval(self::yuanToFen(round($yuanAmount, 2)));
        }
        return self::fenToYuan($fenAmountTotal);
    }

由于本地安装php7.1版本测试未发现相同现象,仔细对比服务器上配置后发现是由于precision配置项被改成-1所致。

输入图片说明

输入图片说明

综上,虽然这个问题主要原因是随意修改配置,且测试服务器php版本比生产环境的7.0版本高,但是生产环境也出现过浮点数精度导致的bug。因此,如果项目对浮点数精度要求严格,尤其是金融项目,建议将浮点数转成整型存储和运算,也有利于数据库存储查询的性能,减少不必要的困扰。

转载于:https://my.oschina.net/luoxiaojun1992/blog/917549

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值