为什么JS中0.1+0.2 != 0.3
为什么JS中0.1+0.2 != 0.3
在我曾经的一篇《 javascript入门教程 (2) 》中,讲到JS中数字运算时,我们提到过一个叫做
数字运算中的精度缺失的问题,当时我们只是简单说了下,并未对其原因做了解。这篇文章,我就带着大家了解下JS运算中精度的缺失问题。
首先我们先来看一个例子
console.log(0.1 + 0.2) // 结果是0.30000000000000004,而不是3
这里0.1 + 0.2 != 0.3 这个就是我们要解决的问题了。
要弄清这个问题的原因,首先我们需要了解下在计算机中数字是如何存储和运算的。在计算机中,数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。在JS中数字采用的IEEE 754的双精度标准进行存储,我们可以无需知道他的存储形式,只需要简单的理解成就是存储一个数值所使用的二进制位数比较多而已,这样得到的数会更加精确。
这里为了简单直观,我们使用定点数来说明问题。在定点数中,如果我们以8位二进制来存储数字。
对于整数来说,十进制的35会被存储为:
00100011其代表2^5 + 2^1 + 2^0。
对于纯小数来说,十进制的0.375会被存储为:0.011其代表1/2^2 + 1/2^3=1/4 + 1/8 = 0.375
而对于像0.1这样的数值用二进制表示你就会发现无法整除,最后算下来会是 0.000110011....由于存储空间有限,最后计算机会舍弃后面的数值,所以我们最后就只能得到一个近似值。在JS中采用的IEEE 754的双精度标准也是一样的道理,我们且不管这个标准下的存储方式跟定点数存储有何不同,单单在这一点上他们都是相同的,也就是存储空间有限,当出现这种无法整除的小数的时候就会取一个近似值,在js中如果这个近似值足够近似,那么js就会认为他就是那个值。(比较拗口,举个例子)
console.log(0.1000000000000001)
// 0.1000000000000001 (中间14个0,会打印出它本身)
console.log(0.10000000000000001)
// 0.1 (中间15个0,js会认为这两个值足够接近,所以会显示0.1)
所以我们现在应该可以理解,就是说由于0.1转换成二进制时是无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。
在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的,在他们相加的时候,两个近似值进行了计算,导致最后得到的值是0.30000000000000004,此时对于JS来说,其不够近似于0.3,于是就出现了0.1 + 0.2 != 0.3 这个现象。
当然,也并非所有的近似值相加都得不到正确的结果。有时两个近似值进行计算的时候,得到的值是在JS的近似范围内的,于是就可以得到正确答案。至于哪些值计算后能得到正确结果,哪些不能,我们也不需要去记。最好的方法就是我们想办法规避掉这类小数计算时的精度问题就好了。
那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。
方法也很简单,举个例子:
对于0.1 + 0.02 我们需要转化成 ( 10 + 2 ) / 1e2
对于0.1 * 0.02 我们则转化成 1 * 2 / 1e3
按照这个思路,写个简单的方法就好了。
另外就是如果你在学习前端的过程中有任何问题想要咨询,欢迎关注
LearnInPro的公众号,在上面随时向我提问哦。为什么JS中0.1+0.2 != 0.3的更多相关文章
- 在js中做数字字符串加0补位,效率分析
分类: Jquery/YUI/ExtJs 2010-08-30 11:27 2700人阅读 评论(0) 收藏 举报 functiondate算法语言c 通常遇到的一个问题是日期的“1976-02-03 ...
- 在js中做数字字符串补0
转自(http://blog.csdn.net/aimingoo/article/details/4492592) 通常遇到的一个问题是日期的“1976-02-03 HH:mm:ss”这种格式 ,我的 ...
- js中setTimeout() 时间参数为0
当看到下面 这种setTimeout 设置为0 写法的时候一脸懵逼,完全没用过. var fuc = [1,2,3]; for(var i in fuc){ setTimeout(function() ...
- java、js中实现无限层级的树形结构(类似递归)
js中: var zNodes=[ {id:0,pId:-1,name:"Aaaa"}, {id:1,pId:0,name:"A"}, {id:11,pId:1 ...
- js中要声明变量吗?
你好,js语言是弱类型语言,无需申明即可直接使用,默认是作为全局变量使用的.建议:在function里时应使用var 申明变量,这样改变量仅仅只在function的生存周期内存在,不会污染到,全局控件 ...
- 在JS中关于堆与栈的认识function abc(a){ a=100; } function abc2(arr){ arr[0]=0; }
平常我们的印象中堆与栈就是两种数据结构,栈就是先进后出:堆就是先进先出.下面我就常见的例子做分析: main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main( ...
- 字符串0.在php和js中转换为布尔类型 值是false还是true
在php 中 $a = '0'; $b = (bool)$a; var_dump($a);//输出false 在js中官方说明: Note:If the value parameter is omit ...
- js中的0就是false,非0就是true及案例
在处理js代码判断真假时经常会这么写. 但fun()可能得到的是数字0,这可不是表示的没有值,但是!js中的数字0就是false,非0就是true. 于是0就被无情的当做false了. 已经被这个坑过 ...
- 深入理解 Node.js 中 EventEmitter源码分析(3.0.0版本)
events模块对外提供了一个 EventEmitter 对象,即:events.EventEmitter. EventEmitter 是NodeJS的核心模块events中的类,用于对NodeJS中 ...
- 为什么js中要用void 0 代替undefined
这个是Backbone.js中的一句源码 if (callback !== void 0 && 'context' in opts && opts.context == ...
随机推荐
- 把AspDotNetCoreMvc程序运行在Docker上-part2:修改容器以及发布镜像
在上一个part<把AspDotNetCoreMvc程序运行在Docker上-part1>,已经将成功将aspdotnetcore程序运行在两个不同的容器中,目前两个容器的内容完全相同,只 ...
- C#三大特性之 封装、继承、多态
一.封装: 封装是实现面向对象程序设计的第一步,封装就是将数据或函数等集合在一个个的单元中(我们称之为类).被封装的对象通常被称为抽象数据类型. 封装的意义: 封装的意义在于保护或者防止代码(数据) ...
- 记DateTime.Now.ToString()遇到的一个坑
最近在编写一个程序中遇到的 程序的简要逻辑就是一个timer控件 1.获取当前时间的短时间,例如 13:15 2.使用获取到的短时间去一个列表中查询是否有匹配的,列表中是一串短时间,类似 {" ...
- 撩课-Python-每天5道面试题-第1天
一. 尽可能详细的描述出一个应用软件, 比如QQ, 在计算机中运行时涉及的软硬件, 以及说明我们编程的侧重点? 电脑开机, 从硬盘中(外部存储设备)加载操作系统(系统软件)到内存(内部存储设备), 并 ...
- Android Studio下载/更新SDK
今天安装配置Android Studio的时候,用SDK Manager下载SDK的时候只显示了一个7.0,别的都刷新不出来(被墙了).去网上搜索怎么解决,发现很多帖子的方法已经过时了(跟现在的AS版 ...
- Web安全相关(四):过多发布(Over Posting)
简介 过多发布的内容相对比较简单,因此,我只打算把原文中的一些关键信息翻译一下.原文链接如下: http://www.asp.net/mvc/overview/getting-started/gett ...
- 洛谷P4781 【模板】拉格朗日插值(拉格朗日插值)
题意 题目链接 Sol 记得NJU有个特别强的ACM队叫拉格朗,总感觉少了什么.. 不说了直接扔公式 \[f(x) = \sum_{i = 1}^n y_i \prod_{j \not = i} \f ...
- Linux VPS主机利用Crontab实现定时重启任务
第一.安装Crontab可执行环境 一般的VPS/服务器是支持的,但是有些可能没有支持就需要我们来给予安装. A - centos系统 #安装Crontab yum install vixie-cro ...
- 实现键盘记录的e.Whick和keyCode,兼容FireFox和IE
主要分四个部分第一部分:浏览器的按键事件第二部分:兼容浏览器第三部分:代码实现和优化第四部分:总结 第一部分:浏览器的按键事件 用js实现键盘记录,要关注浏览器的三种按键事件类型,即keydown,k ...
- 微服务实战(三):以MySQL为例,从原理上理解那些所谓的数据库军规
原文链接:微服务化的数据库设计与读写分离(来源:刘超的通俗云计算) 数据库永远是应用最关键的一环,同时越到高并发阶段,数据库往往成为瓶颈,如果数据库表和索引不在一开始就进行良好的设计,则后期数据库横向 ...