php 浮点数比较方法详解


Posted in PHP onMay 05, 2017

浮点数运算精度问题

首先看一个例子:

<?php
$a = 0.1;
$b = 0.9;
$c = 1;
var_dump(($a+$b)==$c);
var_dump(($c-$b)==$a);
?>

$a+$b==$c 返回true,正确
$c-$b==$a 返回false,错误

为什么会这样呢?

运算后,精度为20位时实际返回的内容如下:

<?php
$a = 0.1;
$b = 0.9;
$c = 1;
printf("%.20f", $a+$b); // 1.00000000000000000000
printf("%.20f", $c-$b); // 0.09999999999999997780
?>

$c-$b 为 0.09999999999999997780,因此与0.1比较返回false

出现这个问题是因为浮点数计算涉及精度,当浮点数转为二进制时有可能会造成精度丢失。

浮点数转二进制方法

整数部分采用除以2取余方法

小数部分采用乘以2取整方法

例如:把数字8.5转为二进制

整数部分是8

8/2=4 8%2=0
4/2=2 4%2=0
2/2=1 2%2=0

1比2小,因此不需要计算下去,整数8的二进制为 1000

小数部分是0.5

0.5x2 = 1.0

因取整后小数部分为0,因此不需要再计算下去

小数0.5的二进制为 0.1

8.5的二进制为1000.1

计算数字0.9的二进制

0.9x2=1.8
0.8x2=1.6
0.6x2=1.2
0.2x2=0.4
0.4x2=0.8
0.8x2=1.6

…. 之后不断循环下去,当截取精度为N时,N后的数会被舍去,导致精度丢失。

上例中0.9在转为二进制时精度丢失,导致比较时出现错误。

所以永远不要相信浮点数已精确到最后一位,也永远不要比较两个浮点数是否相等。

正确比较浮点数的方法

1.使用round方法处理后再比较

例子:

<?php
$a = 0.1;
$b = 0.9;
$c = 1;
var_dump(($c-$b)==$a);          // false
var_dump(round(($c-$b),1)==round($a,1)); // true
?>

2.使用高精度运算方法

首先进行运算时,使用高精度的运算方法,这样可以保证精度不丢失。

高精度运算的方法如下:

bcadd 将两个高精度数字相加

bccomp 比较两个高精度数字,返回-1,0,1

bcdiv 将两个高精度数字相除

bcmod 求高精度数字余数

bcmul 将两个高精度数字相乘

bcpow 求高精度数字乘方

bcpowmod 求高精度数字乘方求模

bcscale 配置默认小数点位数,相当于Linux bc中的”scale=”

bcsqrt 求高精度数字平方根

bcsub 将两个高精度数字相减

例子:

<?php
$a = 0.1;
$b = 0.9;
$c = 1;
var_dump(($c-$b)==$a);     // false
var_dump(bcsub($c, $b, 1)==$a); // true
?>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

PHP 相关文章推荐
一个自定义位数的php多用户计数器代码
Mar 11 PHP
discuz安全提问算法
Jun 06 PHP
功能齐全的PHP发送邮件类代码附详细说明
Jul 10 PHP
Linux下将excel数据导入到mssql数据库中的方法
Feb 08 PHP
解析php如何将日志写进syslog
Jun 28 PHP
ThinkPHP模板Switch标签用法示例
Jun 30 PHP
PHP的Json中文处理解决方案
Sep 29 PHP
万能的php分页类
Jul 06 PHP
PHP常用字符串函数小结(推荐)
Aug 05 PHP
PHP格式化显示时间date()函数代码
Oct 03 PHP
PHP7 echo和print语句实例用法
Feb 15 PHP
php生成word并下载代码实例
Mar 15 PHP
PHP删除二维数组中相同元素及数组重复值的方法示例
May 05 #PHP
完美解决在ThinkPHP控制器中命名空间的问题
May 05 #PHP
Yii2配置Nginx伪静态的方法
May 05 #PHP
php生成网页桌面快捷方式
May 05 #PHP
php 如何设置一个严格控制过期时间的session
May 05 #PHP
php 数组元素快速去重
May 05 #PHP
Yii2实现自定义独立验证器的方法
May 05 #PHP
You might like
php中突破基于HTTP_REFERER的防盗链措施(stream_context_create)
2011/03/29 PHP
基于php验证码函数的使用示例
2013/05/03 PHP
destoon整合ucenter后注册页面不跳转的解决方法
2014/06/21 PHP
PHP 中使用ajax时一些常见错误总结整理
2017/02/27 PHP
ie和firefox中img对象区别的困惑
2006/12/27 Javascript
Some tips of wmi scripting in jscript (1)
2007/04/03 Javascript
一些mootools的学习资源
2010/02/07 Javascript
javascript基础第一章 JavaScript与用户端
2010/07/22 Javascript
用于deeplink的js方法(判断手机是否安装app)
2014/04/02 Javascript
页面刷新时记住滚动条的位置jquery代码
2014/06/17 Javascript
javascript轻量级库createjs使用Easel实现拖拽效果
2016/02/19 Javascript
JS封装的自动创建表格的实现代码
2016/06/15 Javascript
jQuery插件Easyui设置datagrid的pageNumber导致两次请求问题的解决方法
2016/08/06 Javascript
jQuery事件用法详解
2016/10/06 Javascript
bootstrap基础知识学习笔记
2016/11/02 Javascript
Nodejs基于LRU算法实现的缓存处理操作示例
2017/03/17 NodeJs
JS闭包用法实例分析
2017/03/27 Javascript
Angular中封装fancyBox(图片预览)遇到问题小结
2017/09/01 Javascript
Vue表单及表单绑定方法
2018/09/04 Javascript
详解Vue底部导航栏组件
2019/05/02 Javascript
JavaScript单线程和任务队列原理解析
2020/02/04 Javascript
js实现简单点赞操作
2020/03/17 Javascript
[09:34]2018DOTA2国际邀请赛寻真——永不放弃的iG
2018/08/14 DOTA
Python随机生成带特殊字符的密码
2016/03/02 Python
python issubclass 和 isinstance函数
2019/07/25 Python
Python安装依赖(包)模块方法详解
2020/02/14 Python
pycharm中导入模块错误时提示Try to run this command from the system terminal
2020/03/26 Python
浅谈matplotlib中FigureCanvasXAgg的用法
2020/06/16 Python
python中取绝对值简单方法总结
2020/07/24 Python
使用HTML5 Canvas绘制直线或折线等线条的方法讲解
2016/03/14 HTML / CSS
在家更换处方镜片:Lensabl
2019/05/01 全球购物
见习期自我鉴定
2013/11/07 职场文书
2014年学生会个人工作总结
2014/11/07 职场文书
导游词之介休绵山
2019/12/31 职场文书
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
2021/06/09 Vue.js
Python实现批量将文件复制到新的目录中再修改名称
2022/04/12 Python