php关于金额比较引发的问题(转)
做电子商务的时候一般会涉及到金额的比较,按正常的思路来看用><=这些个符号就可以了。可是要是到程序上来搞这个的话就出大事了。现在看下这段代码:
$f = 0.07;
var_dump($f * 100 == 7);//输出false
输出结果会出乎大家意料,输出false,为什么会这样呢?其实这个和电脑中存储小数的原理有关。大家都知道计算机只能存储0和1,我们日常生活习惯使用的是10进制的数据,像0.07这个小数在计算机中存储时会有精度损失,以至于计算出来的结果会有偏差。
那么怎么解决这个问题?虽然计算机存储小数有偏差,但是偏差还是非常小,像上例中0.07 * 100如果显示出小数点后面20位的话,最终的值如下
$f = 0.07;//输出7.00000000000000088818echo number_format($f * 100, 20)$f = 0.07;var_dump($f * 100 == 7);//输出0,表示两个数字精度为小数点后3位的时候相等var_dump(bccomp($f * 100, 7, 3));$bin = "";$int = 7;$base = 100;echo "<table border='1'>";echo "<td width='50'>位数</td>";echo "<td width='50'>x2</td>";echo "<td width='50'>位值</td>";for ($i = 0; $i <= 60; $i++) { echo "<tr>"; echo "<td>$i</td>"; $int = $int * 2; echo "<td>$int</td>"; if ($int == 100) { $bin.="1"; echo "<td>1</td>"; break; } if ($int > 100) { $bin.="1"; $int = $int - $base; echo "<td>1</td>"; } else { $bin .= "0"; echo "<td>0</td>"; } echo "</td>"; echo "</tr>";}echo "</table>";echo $bin;/* 输出内容 0.070000000000000006661338147751 0.070000000000000006661338147751 */$f = 0.0;$bin = "0001000111101011100001010001111010111000010100011110101110000";$l = strlen($bin);for ($i = 0; $i < $l; $i++) { if ($bin[$i] > 0) { $f = $f + pow(2, -($i + 1)); }}echo number_format($f, 30);$f = 0.07;echo "<br />";echo number_format($f, 30);bcadd — 将两个高精度数字相加
bccomp — 比较两个高精度数字,返回-1, 0, 1
bcdiv — 将两个高精度数字相除
bcmod — 求高精度数字余数
bcmul — 将两个高精度数字相乘
bcpow — 求高精度数字乘方
bcpowmod — 求高精度数字乘方求模,数论里非常常用
bcscale — 配置默认小数点位数,相当于就是Linux bc中的”scale=”
bcsqrt — 求高精度数字平方根
bcsub — 将两个高精度数字相减
整理了一些实例
php BC高精确度函数库包含了:相加,比较,相除,相减,求余,相乘,n次方,配置默认小数点数目,求平方。这些函数在涉及到有关金钱计算时比较有用,比如电商的价格计算。
/**
* 两个高精度数比较
*
* @access global
* @param float $left
* @param float $right
* @param int $scale 精确到的小数点位数
*
* @return int $left==$right 返回 0 | $left<$right 返回 -1 | $left>$right 返回 1
*/
var_dump(bccomp($left=4.45, $right=5.54, ));
// -1 /**
* 两个高精度数相加
*
* @access global
* @param float $left
* @param float $right
* @param int $scale 精确到的小数点位数
*
* @return string
*/
var_dump(bcadd($left=1.0321456, $right=0.0243456, ));
//1.04 /**
* 两个高精度数相减
*
* @access global
* @param float $left
* @param float $right
* @param int $scale 精确到的小数点位数
*
* @return string
*/
var_dump(bcsub($left=1.0321456, $right=3.0123456, ));
//-1.98 /**
* 两个高精度数相除
*
* @access global
* @param float $left
* @param float $right
* @param int $scale 精确到的小数点位数
*
* @return string
*/
var_dump(bcdiv($left=, $right=, ));
//1.20 /**
* 两个高精度数相乘
*
* @access global
* @param float $left
* @param float $right
* @param int $scale 精确到的小数点位数
*
* @return string
*/
var_dump(bcmul($left=3.1415926, $right=2.4569874566, ));
//7.71 /**
* 设置bc函数的小数点位数
*
* @access global
* @param int $scale 精确到的小数点位数
*
* @return void
*/
bcscale();
var_dump(bcdiv('', '6.55957'));
// 16.007
php关于金额比较引发的问题(转)的更多相关文章
- 数据库 SQL :有关 NULL 值引发 TRUE、FALSE、UNKNOW 三值逻辑
在 Java.C# 中,相信如果是 boolean 类型值,只有两种选择 true.false.然而,在 SQL 查询中,NULL 值的引入,使得新增了 UNKNOW ,因此,就产生了 TRUE.FA ...
- [WCF]缺少一行代码引发的血案
这是今天作项目支持的发现的一个关于WCF的问题,虽然最终我只是添加了一行代码就解决了这个问题,但是整个纠错过程是痛苦的,甚至最终发现这个问题都具有偶然性.具体来说,这是一个关于如何自动为服务接口(契约 ...
- dubbox微服务实例及引发的“血案”
Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成. 主要核心部件: Remoting: 网络通信框架 ...
- 安全防范:nginx下git引发的隐私泄露问题
安全防范:nginx下git引发的隐私泄露问题 1 安全事件 最近阿里云服务器后台管理系统中收到一条安全提示消息,系统配置信息泄露: http://my.domain.com/.git/confi ...
- Integer.parseInt 引发的血案
Integer.parseInt 处理一个空字符串, 结果出错了, 程序没有注意到,搞了很久, 引发了血案啊!! 最后,终于 观察到了, 最后的部分: Caused by: java.lang.NoC ...
- 选择目录,选择文件夹的COM组件问题。在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。
异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. ...
- 【手记】调用Process.EnterDebugMode引发异常:并非所有引用的特权或组都分配给呼叫方
刚上线一个新版本,其中有台电脑打开软件就报[xx的类型初始值设定项引发异常](还好不是一大波电脑,新东西上线就怕哀鸿遍野),如图: 显然是该类型的静态构造函数中抛异常了(红线处就是类名),遂打开该类, ...
- BPM实例分享——金额规则大写
金额规则大写 在涉及金额的流程中经常会遇到需要大写金额数据与小写金额匹配,如何实现输入数字后自动转换呢? 初级用法: 1.在默认表单基本属性javascript 中增加如下金额转换方法 /** 数字金 ...
- jquery 金额转换成大写
<script language="javascript" type="text/javascript"> function Ara ...
随机推荐
- SQL SERVER 索引之聚集索引和非聚集索引的描述
索引是与表或视图关联的磁盘上结构,可以加快从表或视图中检索行的速度. 索引包含由表或视图中的一列或多列生成的键. 这些键存储在一个结构(B 树)中,使 SQL Server 可以快速有效地查找与键值关 ...
- Visual Studio 2015的Web扩展包
过去几年,Visual Studio扩展功能生态系统得到了蓬勃发展,社区贡献出了大量优秀的扩展,其中也包括大量针对Web开发的扩展.但是很多时候,感觉寻找.安装.更新好 几个扩展,总显得比较麻烦.如果 ...
- Juery Ajax语法
$.ajax({ url: "/ForgetCard/ForgetLogin",//方法路径URL data: { strUser: $("#textUser" ...
- 动软MySQL存储过程模板
<#@ template language="c#" HostSpecific="True" #><#@ output extension= ...
- [SQL]查询及删除重复记录的SQL语句
一:查询及删除重复记录的SQL语句1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断select * from peoplewhere peopleId in (select ...
- 配置ogg目录索引-oracle与mysql的双向同步步骤
以下几篇文章描述了利用ogg对oracle与mysql进行双向同步的配置过程以及注意事项,欢迎参考. 配置ogg异构oracle-mysql(1)基础环境配置 http://www.cnblogs.c ...
- document对象(二)
五.相关元素操作: var a = document.getElementById("id"); 找到a: var b = a.nextSibling ...
- yaml官方介绍
官方网站 http://yaml.org/ 数据结构类型说明 http://yaml.org/type/ YAML Specification http://yaml.org/spec/
- python 线程之_thread
python 线程之_thread _thread module: 基本用法: def child(tid): print("hello from child",tid) _thr ...
- spring4 mvc 出错
java.lang.IncompatibleClassChangeError: class org.springframework.core.type.classreading.ClassMetada ...