当前位置:网站首页>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
边栏推荐
- How does feign integrate hystrix
- Redis--为什么字符串emstr的字符串长度是44字节上限?
- Analysis of Nacos source code
- 三星,再次“西征”
- MYSQL——第一章节(数据类型2)
- 使用 Ingress 实现金丝雀发布
- [problem solving] vs2019 solves the problem that the EXE file generated by compilation cannot be opened
- 【编程实践/嵌入式比赛】嵌入式比赛学习记录(二):基于TCP的图片流传输
- Intranet penetration series: icmptunnel of Intranet tunnel (Master James Barlow's)
- Research on system and software security (3)
猜你喜欢

C problem of marking the position of polygons surrounded by multiple rectangles

yum源仓库本地搭建的两种方法
![[programming practice / embedded competition] learning record of embedded competition (II): picture streaming based on TCP](/img/6c/7408180d0c24560b4a68982635520e.jpg)
[programming practice / embedded competition] learning record of embedded competition (II): picture streaming based on TCP

How does Apache Hudi accelerate traditional batch mode?

巨头押注的全屋智能,正在驱动海信、华为、小米们「自我革命」

Buuctf misc brush questions

Intranet penetration series: icmptunnel of Intranet tunnel (Master James Barlow's)

Intranet penetration series: icmptunnel of Intranet tunnel (by master dhavalkapil)

BUUCTF MISC刷題

Go语学习笔记 - 语言接口 | 从零开始Go语言
随机推荐
Complete color conversion formulas and conversion tables (31 kinds)
Research on system and software security (3)
Redis transaction implements optimistic locking principle
Principle of sentinel integrating Nacos to update data dynamically
爬虫学习笔记,学习爬虫,看本篇就够了
MySQL——第一章节(MySQL中的数据类型)
【编程实践/嵌入式比赛】嵌入式比赛学习记录(二):基于TCP的图片流传输
LeetCoed18. 四数之和
Ctf-misc learning from start to give up
Concours de compétences en informatique en nuage - - première partie de l'environnement cloud privé openstack
内网渗透系列:内网隧道之icmptunnel(DhavalKapil师傅的)
Sto with billing cross company inventory dump return
数据库之Mysql——概述安装篇
Buctf MISC brossage
从ES、MongoDB、Redis、RocketMQ出发谈分布式存储
Talk about the essence of interface idempotent and consumption idempotent
一些靶场的学习记录:sqli-labs、upload-labs、XSS
Internal network security attack and defense: a practical guide to penetration testing (IV): Authority improvement analysis and defense
Three minutes to teach you to use Houdini fluid > > to solve particle fluid droplets
Internal network security attack and defense: a practical guide to penetration testing (8): Authority maintenance analysis and defense