php在进行浮点数计算时结果并不一定是精确到了最后一位,intval(0.58*100) 输出 57 而不是58的问题原因以及php精确计算函数的应用bcadd,bcsub,bcmul,bcdiv,bcmod,bccomp
php在进行浮点数计算时结果并不一定是精确到了最后一位。
例一:
<?php
$a =0.1;
$b = 0.7;
var_dump(($a + $b) == 0.8);
//打印的结果竟然是boolean false
例二:
<?php
intval(0.68*100)输出 68
intval(0.56*100)输出 56
intval(0.57*100)输出 56
intval(0.58*100)输出 57
intval(0.59*100)输出 59
上边例二中只是0.57*100和0.58*100会特殊?
因为计算机中保存浮点数不能精确表示,以十进制能够精确表示的有理数如 0.1 或 0.7,无论有多少尾数都不能被内部所使用的二进制精确表示,因此不能在不丢失一点点精度的情况下转换为二进制的格式。这就会造成混乱的结果:例如,floor((0.1+0.7)*10) 通常会返回 7 而不是预期中的 8,因为该结果内部的表示其实是类似 7.9999999999999991118…
intval(0.58*100); 存储的并不是58而是 57.99999999999999…,这不局限于任何语言的,是 IEEE 规定的浮点数的运算标准。
一般情况下,57.99999999999999 会四舍五入到 58。浮点数的四舍五入和普通的数学里面的有时候不一样,浮点数遇到 5 后,不一定总是入,有时也会舍,intval 函数的规则是,从第一个数字开始,直到遇到不是数字的字符结束,intval是截取了,一般解决方法是让计算后的值先转为字符串,再对字符串转整型:intval(strval(0.58*100));这样结果为58。
所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数。
比如PHP中的,加:bcadd,减:bcsub,乘:bcmul,除:bcdiv,求余/取模:bcmod,:比较大小:bccomp。
例一可以转换为:
<?php
$a = 0.1;
$b = 0.7;
var_dump(bcadd($a,$b,2) == 0.8);
// 打印结果boolean true
例二转换为:intval(bcmul(0.58,100));
函数应用:
<?php
/**
* 精确加法
* @param [type] $a [description]
* @param [type] $b [description]
*/
function math_add($a,$b,$scale = '2') {
return bcadd($a,$b,$scale);
}
/**
* 精确减法
* @param [type] $a [description]
* @param [type] $b [description]
*/
function math_sub($a,$b,$scale = '2') {
return bcsub($a,$b,$scale);
}
/**
* 精确乘法
* @param [type] $a [description]
* @param [type] $b [description]
*/
function math_mul($a,$b,$scale = '2') {
return bcmul($a,$b,$scale);
}
/**
* 精确除法
* @param [type] $a [description]
* @param [type] $b [description]
*/
function math_div($a,$b,$scale = '2') {
return bcdiv($a,$b,$scale);
}
/**
* 精确求余/取模
* @param [type] $a [description]
* @param [type] $b [description]
*/
function math_mod($a,$b) {
return bcmod($a,$b);
}
/**
* 比较大小
* @param [type] $a [description]
* @param [type] $b [description]
* 大于 返回 1 等于返回 0 小于返回 -1
*/
function math_comp($a,$b,$scale = '5') {
return bccomp($a,$b,$scale); // 比较到小数点位数
}
echo math_add('3.445','3.444')."\n"; // 加 6.88
echo math_sub('3.445','3.444')."\n"; // 减 0.00
echo math_mul('3.445','3.444')."\n"; // 乘 11.86
echo math_div('3.445','3.444')."\n"; // 除 1.00
echo math_mod('3.445','3.444')."\n"; // 取模 0
echo math_comp('3.445','3.444')."\n";// 比较 1
echo math_add('3.445','3.444','3')."\n"; // 加 6.889
echo math_sub('3.445','3.444','3')."\n"; // 减 0.001
echo math_mul('3.445','3.444','3')."\n"; // 乘 11.864
echo math_div('3.445','3.444','3')."\n"; // 除 1.000
echo math_mod('3.445','3.444')."\n"; // 取模 0
echo math_comp('3.445','3.444')."\n";// 比较 1