先来个简单的代码片段:

> console.log(0.1 + 0.2)
> 0.30000000000000004

好奇怪的结果,怎么会是0.30000000000000004呢?难道是Javascript语言的bug还是chrome dev tools的bug?

其实,这不是语言的bug或者宿主环境的bug。目前所有的程序设计语言在对浮点数进行四则运算时,都会涉及到浮点数精确度的问题。

我们知道在计算机的世界中,计算机只认识0,1,我们传入的十进制数字并不会被计算机直接识别。计算机会先将其转换成二进制,然后使用转换后的二进制进行计算。

那么0.1和0.2转换成二进制分别是,

(0.1) => 0.0001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 1001 101

(0.2) => 0.0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 01

然后对上面的两个二进制数字做加法,得到的结果是,

0.0100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1100 1101 01

再把这个二进制转换成十进制,就是我们前面的结果0.30000000000000004了。

计算机世界的数值计算基本上都是这个过程,只不过C++、C#、Java这些传统强类型语言将这个边界问题封装在内部了,它们在进行浮点数四则运算时,会在语言层面自动解决这个问题。而Javascript作为一门弱类型的语言,它在语言层面并没有对这个问题进行处理,所以需要我们手动去处理。

那么,我们如何去避免这个问题呢?

基本上有两种思路。

先扩大数值到javascript可精确识别的精度级别(比如个位数级别)然后再进行计算,然后再对结果除以放大的倍数。

在运算的过程中通过toFixed()指定运算的精度要求。

比如我们要计算0.1 + 0.2,按照第一种思路,我们可以这么来做,

var a = 0.1;

var b = 0.2;

var ret = (a * 10 + b * 10) / 10;

console.log(ret);

这里,我们在计算之前,现将a和b乘以10(放大10倍,当然放大100、1000倍也是可以的),此时a和b已经不再是浮点数了,整数的四则运算当然是不需要考虑精度问题啦。最后我们还需要除以之前放大的倍数,得到正确的最终结果。其实这是一种迂回的办法来规避掉浮点数的四则运算精度问题。

按照第二种思路,我们可以这么来做,

var a = 0.1;

var b = 0.2;

var ret = (a + b).toFixed(1);

var ret = parseFloat(ret);

注意toFixed()返回的是一个String,所以我们还需要进行parseFloat或Number操作。

附上针对js浮点运算的公共方法:

var util = {/**
* 加法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcAdd: function(arg1, arg2) {
var r1,r2,m;
try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}
try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}
m=Math.pow(10,Math.max(r1,r2));
return (arg1*m+arg2*m)/m;
},/**
* 减法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcSub: function accSub(arg1, arg2) {
var r1,r2,m,n;
try{r1=arg2.toString().split(".")[1].length}catch(e){r1=0}
try{r2=arg1.toString().split(".")[1].length}catch(e){r2=0}
m=Math.pow(10,Math.max(r1,r2));
//last modify by deeka
//动态控制精度长度
n=(r1>=r2)?r1:r2;
return ((arg1*m-arg2*m)/m).toFixed(n);
},/**
* 乘法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcMul: function accMul(arg1, arg2) {
var m=0,s1=arg1.toString(),s2=arg2.toString();
try{m+=s1.split(".")[1].length}catch(e){}
try{m+=s2.split(".")[1].length}catch(e){}
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m);
},/**
* 除法优化,避免浮点误差
* @param arg1
* @param arg2
* @returns {String}
*/
calcDiv: function accDiv(arg1, arg2) {
var t1=0,t2=0,r1,r2;
try{t1=arg1.toString().split(".")[1].length}catch(e){}
try{t2=arg2.toString().split(".")[1].length}catch(e){}
r1=Number(arg1.toString().replace(".",""));
r2=Number(arg2.toString().replace(".",""));
return (r1/r2)*Math.pow(10,t2-t1);
}};

简化版:

var util = (function(){var getFuncByType = function(typeText){return new Function('a', 'b', 'var aR = 0, bR = 0;try{aR = Number(a).toString().split(".")[1].length;}catch(e){}try{bR = Number(b).toString().split(".")[1].length;}catch(e){}return Number((a'+ typeText +'b).toFixed(aR+bR));');};return {// 加calcAdd: function(a, b){return getFuncByType("+")(a, b);},// 减calcSub: function(a, b){return getFuncByType("-")(a, b);},// 乘calcMul: function(a, b){return getFuncByType("*")(a, b);},// 除calcDiv: function(a, b){return getFuncByType("/")(a, b);}}})();

转载于:https://www.cnblogs.com/mjian/p/9250149.html

JS中浮点数运算误差处理相关推荐

  1. js中浮点数运算精度问题

    在js中,我们有时会遇到计算,通过加减乘除处理某些业务.那么这时候如果不做任何处理,就会出现如下典型的精度丢失问题. console.log(0.1 + 0.2) ; // 0.30000000000 ...

  2. js浮点数精度丢失问题及如何解决js中浮点数计算不精准

    js浮点数精度丢失问题及如何解决js中浮点数计算不精准 参考文章: (1)js浮点数精度丢失问题及如何解决js中浮点数计算不精准 (2)https://www.cnblogs.com/ranyonsu ...

  3. GPU与CPU浮点数运算误差不同

    在写CUDA程序时发现,GPU与CPU浮点数运算的误差有差异. 上图为GPU计算结果(76.5733337, -63.2816696,19.7351151,10847.6279) 下图为CPU计算结果 ...

  4. python浮点数怎么运算_为什么说浮点数缺乏精确性? python中浮点数运算问题

    我想从两个角度回答: 一:十进制小数转化成二进制小数的方法.(简单举例,看完就可以自己用笔进行运算.) 二:如何解决python中的浮点数运算问题. 关于一: 拿1.375这个十进制数举例,pytho ...

  5. 计算机浮点数运算误差与解决误差的算法

    1.  浮点数IEEE 754表示方法 要搞清楚float累加为什么会产生误差,必须先大致理解float在机器里怎么存储的,这里只介绍一下组成 由上图可知(摘在[2]), 浮点数由: 符号位 + 指数 ...

  6. js中浮点型运算 加减乘除

    <script> //加法函数,用来得到精确的加法结果 //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精确的加法结果. //调用:ac ...

  7. js中float运算

    /浮点数加法运算 function FloatAdd(arg1,arg2){ var r1,r2,m; try{r1=arg1.toString().split(".")[1].l ...

  8. 【linux】shell中浮点数运算的加、减、乘、除

    bash 不支持浮点运算,如果需要进行浮点运算,需要借助bc,awk 处理. 1.bc #!/bin/bash#加 f=$(echo "4.3+2.5"|bc) echo &quo ...

  9. JS中的运算符号(加号)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

最新文章

  1. 宅家学习,如何进行Kubernetes Ingress控制器的技术选型?
  2. 【Node核心模块HTTP】
  3. Spring之LoadTimeWeaver——一个需求引发的思考---转
  4. boost::remove_edge_if用法的测试程序
  5. jsp 防止sql注入 之 preparestatement篇(转载)
  6. 展示 测速_科技产品 | 人工智能amp;科技展示厅——助力高校人工智能学科建设及产业人才培养...
  7. mysql高级查询 二_MySQL高级查询(二)
  8. linux微信公众号报警,zabbix报警媒介,微信报警,邮件报警
  9. sql/c#十六进制与十进制的转换
  10. js 递归查询所有的叶子结点_浅谈mysql的查询过程
  11. android 结束if循环_简单探究Android平台下' if ' 语句条件判断耗时情况
  12. 案例分享|数据可视化下的驱动业务增长
  13. 0610PHP基础:运算符、字符串处理函数、解析符号、数组
  14. 将稍大文件存储到远程SQL Server服务器
  15. python重要性_基于Python的随机森林特征重要性图
  16. ae遮罩路径图形扭曲插件BAO Boa
  17. matlab掷色子游戏,掷骰子游戏四种玩法_聚会游戏必备
  18. PIXHAWK飞行模式
  19. python数据分析18-21
  20. Java抓取网页图片

热门文章

  1. 直方图 帕累托图_工具讲解 | 用Excel绘制帕累托图
  2. 计算机网络管理2018版,2018~2019学年度第二学期“计算机网络管理”专业技能竞赛火热进行中...
  3. python第三方库文件传输_本地 Python 代码上传到 Python 第三方库(Pypi)
  4. 用 js判断 一个数是否是素数(质数)_小学五年级下册数学公式打印版,孩子寒假预习用的上!...
  5. python生成json_python中如何进行json转化
  6. java小数左右移_Java将小数位移至两倍
  7. php单选框点击取消,取消选中单选框radio的三种方式
  8. Caused by: java.net.ConnectException: Connection refused: no further information
  9. linux下的shell多线程用法,shell多线程操作
  10. 东北大学c语言编程尸体,东北大学c语言编程试题及其答案