当前位置:网站首页>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
边栏推荐
- Chapter VII asset impairment
- 云计算赛项--2020年赛题基础部分[任务3]
- 攻防世界MISC刷题1-50
- Mysql database backup and recovery under Linux (full + incremental)
- Research on system and software security (5)
- Concours de compétences en informatique en nuage - - première partie de l'environnement cloud privé openstack
- 一些关于网络安全的好教程或笔记的链接,记录一下
- Expression related to month, year and day in SVG
- Go语学习笔记 - 语言接口 | 从零开始Go语言
- CSV Column Extract列提取
猜你喜欢

Concours de compétences en informatique en nuage - - première partie de l'environnement cloud privé openstack

Go语学习笔记 - 语言接口 | 从零开始Go语言
![[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

惨了,搞坏了领导的机密文件,吐血分享备份文件的代码技巧

Construction of middleman environment mitmproxy

Attack and defense world misc questions 1-50

BUUCTF MISC刷题

Using lambda expression to solve the problem of C file name sorting (whether it is 100 or 11)

Ctf-misc summary

Research on software security based on NLP (2)
随机推荐
Intranet penetration series: dnscat2 of Intranet tunnel
数据库之Mysql——概述安装篇
LeetCode15. 三数之和
Chapter V investment real estate
Concours de compétences en informatique en nuage - - première partie de l'environnement cloud privé openstack
一文了解系列,对web渗透的常见漏洞总结(持续更新)
Internal network security attack and defense: a practical guide to penetration testing (VII): cross domain attack analysis and defense
Link to some good tutorials or notes about network security and record them
Mobile terminal layout (3D conversion, animation)
Cloud computing skills competition -- Part 2 of openstack private cloud environment
Dvwa 靶场练习记录
C 输出一种二维数组,特点如下。
Complete learning from scratch, machine learning and deep learning, including theory and code implementation, mainly using scikit and mxnet, and some practices (on kaggle)
Guoji Beisheng openstack container cloud environment construction
Sto with billing cross company inventory dump return
SAP GUI security
MySQL——第一章节(MySQL中的数据类型)
攻防世界MISC刷题1-50
LeetCoed18. 四数之和
云计算赛项--2020年赛题基础部分[任务3]