当前位置:网站首页>php高精度计算
php高精度计算
2022-04-23 06:45:00 【赫赫phper】
一、前方有坑
php在使用加减乘除等运算符计算浮点数的时候,经常会出现意想不到的结果,特别是关于财务数据方面的计算,给不少工程师惹了很多的麻烦。比如今天工作终于到的一个案例:
$a = 2586;
$b = 2585.98;
var_dump($a-$b);
期望的结果是:float(0.02)
实际结果:
float(0.019999999999982)
人生有坑,处处提防
二、防坑攻略:
1、通过乘100的方式转化为整数加减,然后在除以100转化回来……
2、使用number_format转化成字符串,然后在使用(float)强转回来……
3、php提供了高精度计算的函数库,实际上就是为了解决这个浮点数计算问题而生的。
主要函数有:
bcadd — 将两个高精度数字相加
bccomp — 比较两个高精度数字,返回-1, 0, 1
bcdiv — 将两个高精度数字相除
bcmod — 求高精度数字余数
bcmul — 将两个高精度数字相乘
bcpow — 求高精度数字乘方
bcpowmod — 求高精度数字乘方求模,数论里非常常用
bcscale — 配置默认小数点位数,相当于就是Linux bc中的”scale=”
bcsqrt — 求高精度数字平方根
bcsub — 将两个高精度数字相减
前两种流氓的办法就不测试了,使用bcsub测试第三种两数相减的例子,
先看bcsub用法(来自官网)
string bcsub ( string $left_operand , string $right_operand [, int $scale = int ] )
参数
left_operand 字符串类型的左操作数.
right_operand 字符串类型的右操作数.
scale 此可选参数用于设置结果中小数点后的小数位数。也可通过使用 bcscale() 来设置全局默认的小数位数,用于所有函数。
返回值 返回减法之后结果为字符串类型.
测试代码:
var_dump(bcsub($a,$b,2));
结果
0.02
其他的函数请参考PHP官方网站
三、为啥有坑:
php的bug?不是,这是所有语言基本上都会遇到的问题,所以基本上大部分语言都提供了精准计算的类库或函数库。
要搞明白这个原因, 首先我们要知道浮点数的表示(IEEE 754):
浮点数, 以64位的长度(双精度)为例, 会采用1位符号位(E), 11指数位(Q), 52位尾数(M)表示(一共64位).
符号位:最高位表示数据的正负,0表示正数,1表示负数。
指数位:表示数据以2为底的幂,指数采用偏移码表示
尾数:表示数据小数点后的有效数字.
这里的关键点就在于, 小数在二进制的表示, 小数如何转化为二进制呢?
算法是乘以2直到没有了小数为止。这里举个例子,0.9表示成二进制数
0.9*2=1.8 取整数部分 1
0.8(1.8的小数部分)*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 0
.........
0.9二进制表示为(从上往下): 1100100100100......
注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。这也就解释了为什么浮点型减法出现了"减不尽"的精度丢失问题。
换句话说:我们看到十进制小数,在计算机内存储的不是一个精确的数字,也不可能精确。所以在数字加减乘除后出现意想不到的结果。
四、防坑提示
基于以上原因,所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。如果确实需要更高的精度,应该使用任意精度数学函数或者 gmp 函数
版权声明
本文为[赫赫phper]所创,转载请带上原文链接,感谢
https://blog.csdn.net/hechenhongbo/article/details/124173496
边栏推荐
- Intranet penetration series: icmpsh of Intranet tunnel
- MySQL--锁的奥秘--数据怎么锁
- 内网渗透系列:内网隧道之icmp_tran
- Research on software security based on NLP (2)
- BUUCTF [ACTF2020 新生赛]Include1
- Codeforces Round #784 (Div. 4)
- [problem solving] vs2019 solves the problem that the EXE file generated by compilation cannot be opened
- Ctf-misc summary
- [programming practice / embedded competition] learning record of embedded competition (II): picture streaming based on TCP
- BUUCTF [极客大挑战 2019]EasySQL1
猜你喜欢
LeetCode 1611. 使整数变为 0 的最少操作次数
Mobile terminal layout (3D conversion, animation)
使用 Ingress 实现金丝雀发布
Go语学习笔记 - 数组 | 从零开始Go语言
內網滲透系列:內網隧道之icmpsh
Go语学习笔记 - Slice、Map | 从零开始Go语言
CSV Column Extract列提取
随笔(不定时更新)
Intranet penetration series: icmptunnel of Intranet tunnel (by master dhavalkapil)
SAP tr manual import system operation manual
随机推荐
Positioning and decoration style
Attack and defense world misc questions 1-50
KCD_ EXCEL_ OLE_ TO_ INT_ Convert reports an error sy subrc = 2
Go语学习笔记 - 结构体 | 从零开始Go语言
Principle of sentinel integrating Nacos to update data dynamically
CTF-MISC总结
SAP sto with billing process and configuration
Alibaba sentinel学习QA
DVWA靶场练习
《内网安全攻防:渗透测试实战指南》读书笔记(五):域内横向移动分析及防御
内网渗透系列:内网隧道之icmptunnel(DhavalKapil师傅的)
《内网安全攻防:渗透测试实战指南》读书笔记(八):权限维持分析及防御
Export all SVG files in the specified path into pictures in PNG format (thumbnail or original size)
RGB color to hex and unit conversion
Construction of middleman environment mitmproxy
云计算技能大赛 -- openstack私有云环境 第一部分
strcat()、strcpy()、strcmp()、strlen()
从零开始完整学习机器学习和深度学习,包括理论和代码实现,主要用到scikit和MXNet,还有一些实践(kaggle上的)
Reptile learning notes, learning reptile, read this article is enough
访问数据库的时候出现错误 Operation not allowed for a result set of type ResultSet.TYPE_FORWARD_ONLY.详解