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实现验证码功能
Oct 09 PHP
PHP中GET变量的使用
Oct 09 PHP
来自PHP.NET的入门教程
Oct 09 PHP
dedecms中常见问题修改方法总结
Mar 21 PHP
Discuz 6.0+ 批量注册用户名
Sep 13 PHP
PHP父类调用子类方法的代码例子
Apr 09 PHP
php switch语句多个值匹配同一代码块应用示例
Jul 29 PHP
隐性调用php程序的方法
Jun 13 PHP
详解PHP的Yii框架中组件行为的属性注入和方法注入
Mar 18 PHP
php字符串的替换,分割和连接方法
May 23 PHP
thinkphp制作404跳转页的简单实现方法
Sep 22 PHP
网站被恶意镜像怎么办 php一段代码轻松搞定(全面版)
Oct 23 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
一个更简单的无限级分类菜单代码
2007/01/16 PHP
PHP中for循环语句的几种变型
2007/03/16 PHP
利用php获取服务器时间的实现代码
2013/06/07 PHP
PHP按指定键值对二维数组进行排序的方法
2015/12/22 PHP
PHP中addcslashes与stripcslashes函数用法分析
2016/01/07 PHP
Laravel5.4简单实现app接口Api Token认证方法
2019/08/29 PHP
Cookie跨域问题解决方案代码示例
2020/11/24 PHP
JavaScript更改class和id的方法
2008/10/10 Javascript
JS 强制设为首页的代码
2009/01/31 Javascript
Prototype Selector对象学习
2009/07/23 Javascript
从零开始学习jQuery (十一) 实战表单验证与自动完成提示插件
2011/02/23 Javascript
JQ获取动态加载的图片大小的正确方法分享
2013/11/08 Javascript
jQuery操作input值的各种方法总结
2013/11/21 Javascript
js对文章内容进行分页示例代码
2014/03/05 Javascript
JavaScript中自定义事件用法分析
2014/12/23 Javascript
JS中常用的输出方式(五种)
2016/06/12 Javascript
React中使用UEditor百度富文本的方法
2018/08/22 Javascript
解决angular2 获取到的数据无法实时更新的问题
2018/08/31 Javascript
使用Vue中 v-for循环列表控制按钮隐藏显示功能
2019/04/23 Javascript
微信小程序判断页面是否从其他页面返回的实例代码
2019/07/03 Javascript
WebPack工具运行原理及入门教程
2020/12/02 Javascript
vue实现购物车的小练习
2020/12/21 Vue.js
详解Python中的文件操作
2016/08/28 Python
python生成词云的实现方法(推荐)
2017/06/13 Python
在Python中Dataframe通过print输出多行时显示省略号的实例
2018/12/22 Python
对python列表里的字典元素去重方法详解
2019/01/21 Python
Django haystack实现全文搜索代码示例
2020/11/28 Python
CSS3 三维变形实现立体方块特效源码
2016/12/15 HTML / CSS
html5简介_动力节点Java学院整理
2017/07/07 HTML / CSS
爱尔兰橄榄球店:Irish Rugby Store
2019/12/05 全球购物
九年级历史教学反思
2014/01/27 职场文书
致标枪运动员加油稿
2014/02/15 职场文书
党员岗位承诺书
2014/03/25 职场文书
特种设备安全管理制度
2015/08/06 职场文书
理解python中装饰器的作用
2021/07/21 Python
css 边框添加四个角的实现代码
2021/10/16 HTML / CSS