当前位置: 首页 > 后端技术 > PHP

系统讲解-PHP浮点数高精度计算

时间:2023-03-30 03:44:34 PHP

概述记录,工作中遇到的坑...关于PHP浮点数计算,尤其是金融行业,电商订单管理,数据等相关业务报表等,使用浮点数进行加减乘除时,如果不注意计算结果,就会出现偏差,轻则损失几十万,重则名誉受损,甚至诉讼。我们必须高度重视!浮点运算的“锅”//add$a=0.1;$b=0.7;$c=intval(($a+$b)*10);echo$c."
";//输出:7//减去$a=100;$b=99.98;$c=$a-$b;回显$c."
";//输出:0.019999999999996//乘以$a=0.58;$b=100;$c=intval($a*$b);echo$c."
";//输出:57//除了$a=0.7;$b=0.1;$c=intval($a/$b);echo$c."
";//Output:6上面的结果显然不是我们想要的!PHP官方手册是这样解释的:浮点数精度有限。虽然取决于系统,但PHP通常使用IEEE754双精度格式,那么由于四舍五入导致的最大相对误差为1.11e-16。非基本数学运算可能会产生更大的错误,并在复合运算时考虑错误传播。永远不要相信浮点结果的最后一位,也永远不要比较两个浮点数是否相等。如果你真的需要更高的精度,你应该使用任意精度数学函数或gmp函数。这里的关键是浮点数的小数点是用二进制表示的,其过程是:小数点乘以2,取整数部分表示第一位;小数部分乘以2,取整数部分表示第二位;乘以2,取整数部分代表第三位;...以此类推,直到小数部分为0;示例:0.580.58*2=1.16--->10.16*2=0.32--->00.32*2=0.64--->00.64*2=1.28--->10.28*2=0.56--->00.56*2=1.12--->10.12*2=0.24--->00.24*2=0.48--->00.48*2=0.96--->00.96*2=1.92--->1...我们将得到一个二进制小数的无限循环:0.1001010001...小数部分有一个循环,有限的二进制位不能准确表示一个小数,这就是小数计算出现错误的原因。接下来,我将向您介绍任意精度的数学函数。任意精度数学函数对于任意精度数学,PHP支持对由字符串表示的任意大小和精度的数字进行二进制计算。BCMath:BC是BinaryCalculator的缩写。官方手册:http://php.net/manual/zh/book...使用前请确认是否安装了bcmath。//添加$a=0.1;$b=0.7;$c=intval(bcadd($a,$b,1)*10);echo$c."
";//输出:8//减去$a=100;$b=99.98;$c=bcsub($a,$b,2);echo$c."
";//输出:0.02//乘以$a=0.58;$b=100;$c=intval(bcmul($a,$b));echo$c。"
";//输出:58//except$a=0.7;$b=0.1;$c=intval(bcdiv($a,$b));echo$c."
";//Output:7除了加法,减法,乘法和除法,bcmath还提供了以下方法:bccomp比较两个任意精度数bcmod与任意精度数字模bcpow任意精度数的幂bcpowmod高精度数字幂模bcscale设置为所有bc数学函数保留的默认小数位数Integer)echofloor(5.1);//输出:5echofloor(8.8);//输出:8四舍五入(roundingup)echoceil(5.1);//输出:6echoceil(8.8);//输出:9普通舍入方法echoround(5.1);//输出:5echoround(8.8);//输出:9//保留两位小数并向上舍入echoround(5.123,2);//输出:5.12echoround(8.888,2);//输出:8.89//预留two小数位且不四舍五入echosubstr(round(5.12345,3),0,-1);//Output:5.12echosubstr(round(8.88888,3),0,-1);//Output:8.88庄家取整法四舍五入,如果五后不为空,则向上取整,如果五后为空,检查奇偶性,如果在五前为偶数,则舍去,进阶为奇五点前一点。保留两位小数,例如:1.2849=1.28->四舍五入1.2866=1.29->六位四舍五入1.2851=1.29->如果五位后不为空,则向上取一位1.2850=1.28->五位后为空看奇偶,五前为偶数响应舍入1.2750=1.28->五为空后看奇偶,五前为奇数,实现代码如下:echoround(1.2849,2,PHP_ROUND_HALF_EVEN);//输出:1.28echoround(1.2866,2,PHP_ROUND_HALF_EVEN);//输出:1.29echoround(1.2851,2,PHP_ROUND_HALF_EVEN);//输出:1.29echoround(1.2850,2,PHP_ROUND_HALF_EVEN);//输出:1.28echoround(1.2750,2,PHP_ROUND_HALF_EVEN);//输出:1.28更多round的使用说明,请参考官方手册:http://php.net/manual/zh/func...数值格式化(千位分组)应用于金额的显示,如银行卡余额我们经常看到。echonumber_format('10000.98',2,'.',',');//输出:10,000.98echonumber_format('340888999',2,'.',',');//输出:340,888,999.00扩展MySQL浮点数类型字段在MySQL中,创建表字段时也有浮点数类型。浮点数类型包括单精度浮点数(float)和双精度浮点数(double)。同理,不推荐使用浮点数类型!!!浮点数有错误。当我们使用对精度敏感的数据时,应该使用定点数(十进制)进行存储。小结通过浮点数精度的问题,了解到浮点数的小数点是用二进制表示的。分享了使用PHP任意精度数学函数进行高精度计算。同时分享了常见的数值处理方案,如四舍五入法、四舍五入法、四舍五入法、银行家四舍五入法、数值格式化等。最后通过PHP的float想到了MySQL的float。以后用浮点运算一定要慎重,细节决定成败。推荐阅读系统详解-SSO单点登录系统详解-PHPWEB安全防御系统详解-PHP缓存技术系统详解-PHP接口签名验证一起学习