php精度计算问题

先看段代码:

<?php
    $a = 0.1;
    $b = 0.7;
    echo $a + $b;
    echo '<br>';
    var_dump(($a + $b) == 0.8);
    echo '<br>';
    if(($a + $b) == 0.8){
        echo "相等";
    }else{
        echo "不相等";
    }
?>
    结果:
    0.8
    bool(false) 
    不相等

结果显示不相等,这是为啥?
显然简单的十进制分数如同 0.1 或 0.7 不能在不丢失一点点精度的情况下转换为内部二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999…。
这和一个事实有关,那就是不可能精确的用有限位数表达某些十进制分数。例如,十进制的 1/3 变成了 0.3333333…。

再来看看另一个例子:

<?php
    $f = 0.58;
    var_dump(intval($f * 100)); //为啥输出57
?>

由PHP浮点数运算精度造成的,鸟哥的Bolg有详细的说明。http://www.laruence.com/2013/03/26/2884.html
小数在二进制表示时,0.58对于二进制,是无限长的值

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

转换成浮点数(64位双精度)

0.58 -> 0.57999999999999996
0.57 -> 0.56999999999999995
0.58*100 = 57.999999999 
(int)(0.58*100) = 57 

所以针对以上问题,我们可以使用php有BC高精确度函数库bc是Binary Calculator的缩写。bc*函数的参数都是操作数加上一个可选的 [int scale],比如string bcadd(string left_operand, string right_operand[, int $scale]),如果scale没有提供,就用bcscale的缺省值。这里大数直接用一个由0-9组成的string表示,计算结果返回的也是一个 string。

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

第一个例子改成:
var_dump(bcadd($a,$b,2) == 0.8); //返回true
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值