js为什么不能正确处理小数运算?


Posted in Javascript onDecember 29, 2015
var sum = 0;
for(var i = 0; i < 10; i++) {
 sum += 0.1;
}

console.log(sum);

上面的程序会输出1吗?

你有必要知道的 25 个 JavaScript 面试题 一文中,第 8 个题浅显的说了下 js 为什么不能正确处理小数运算的问题。今天重拾旧题,更深层次的剖析下这个问题。

但要先说明的是,不能正确处理小数的运算并不是 JavaScript 语言本身的设计错误,其它高级编程语言,如C,Java等,也是不能正确处理小数运算的:

#include <stdio.h>

void main(){
  float sum;
  int i;
  
  sum = 0;
  
  for(i = 0; i < 100; i++) {
    sum += 0.1;
  }
  
  printf('%f\n', sum); //10.000002
}

数在计算机内部的表示

我们都知道,用高级编程语言编写的程序需要经过解释、编译等操作转变成 CPU(Central Processing Unit) 可以识别的机器语言才能运行,而对 CPU 来说,它不识别数的十进制、八进制和十六进制等,我们在程序中声明的这些进制数都会被转成二进制数进行运算。

为什么不是转换成三进制数进行运算呢?

计算机内部是由很多的 IC (Integrated Circuit: 集成电路) 这种电子部件构成的,它的长相大概是这样子:

js为什么不能正确处理小数运算?

IC 有很多种形状,在其两侧或内部并排排列着很多引脚(图示只画出了一侧)。IC 的所有引脚,只有直流电压 0V 或 5V 两个状态,即一个 IC 引脚只能表示两个状态。IC 的这个特性就决定了计算机内部的数据只能用二进制数处理。

由于1 位(一个引脚)只能表示两个状态,所以二进制的计算方式就变成了 0、1、10、11、100….这种形式:

js为什么不能正确处理小数运算?

所以,在数的运算中,所有操作数都会被转成二进制数参与运算,如39,会被转换成二进制 00100111

小数的二进制表示

如前文所说,程序中的数据都会被转换成二进制数,小数参与运算时,也会被转成二进制,如十进制的11.1875 会被转换成1101.0010。

小数点后 4 位用二进制数表示的数值范围是 0.0000~0.1111,因此,这只能表示 0.5、0.25、0.125、0.0625 这四个十进制数以及小数点后面的位权组合(相加)而成的小数:

js为什么不能正确处理小数运算?

从上表可以看出,十进制数 0 的下一位是 0.0625,所以,0~0.0625 之间的小数,就无法用小数点后 4 位数的二进制数表示;如果增加二进制数小数点后面的位数,与其相对应的十进制数的个数也会增加,但无论增加多少位,都无法得到 0.1 这个结果。实际上,0.1 转换成二进制是 0.00110011001100110011…… 注意 0011 是无限重复的:

console.log(0.2+0.1);

//操作数的二进制表示
0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)

js 的 Number 类型并没有像 C / Java 等分整型、单精度、双精度等,而是统一表现为双精度浮点型。按照 IEEE 的规定,单精度浮点数用 32 位表示全体小数,而双精度浮点数用 64 位表示全体小数,而浮点数由符号、尾数、指数和基数组成,所以并不是所有的位数都用来表示小数,符号、指数等也要占据位数,基数不占据位数:

js为什么不能正确处理小数运算?

双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100…因浮点数小数位的限制而截断的二进制数字,这时候,再把它转换为十进制,就成了 0.30000000000000004。

总结

js 不能正确处理小数运算,包括其它高级编程语言一样,这不是语言本身的设计错误,而是计算机内部本身就不能正确处理小数的运算,对小数的运算往往会得到意想不到的结果,因为并不是所有的十进制小数能被二进制表示。

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
JSP中使用JavaScript动态插入删除输入框实现代码
Jun 13 Javascript
JQuery插件jcarousellite的参数中文说明
May 11 Javascript
angularjs学习笔记之双向数据绑定
Sep 26 Javascript
几种经典排序算法的JS实现方法
Mar 25 Javascript
浅析Javascript的自动分号插入(ASI)机制
Sep 29 Javascript
selenium 与 chrome 进行qq登录并发邮件操作实例详解
Apr 06 Javascript
利用node.js制作命令行工具方法教程(一)
Jun 22 Javascript
基于JavaScript中字符串的match与replace方法(详解)
Dec 04 Javascript
详解Vue源码学习之双向绑定
Apr 10 Javascript
node 标准输入流和输出流代码实例
Sep 19 Javascript
Vue解析带html标签的字符串为dom的实例
Nov 13 Javascript
Vue执行方法,方法获取data值,设置data值,方法传值操作
Aug 05 Javascript
javascript从作用域链谈闭包
Jul 29 #Javascript
你有必要知道的25个JavaScript面试题
Dec 29 #Javascript
JavaScript仿支付宝密码输入框
Dec 29 #Javascript
js实现商城星星评分的效果
Dec 29 #Javascript
原生js配合cookie制作保存路径的拖拽
Dec 29 #Javascript
一种新的javascript对象创建方式Object.create()
Dec 28 #Javascript
JavaScrip常见的一些算法总结
Dec 28 #Javascript
You might like
以文本方式上传二进制文件的PHP程序
2006/10/09 PHP
PHP中date与gmdate的区别及默认时区设置
2014/05/12 PHP
Yii配置与使用memcached缓存的方法
2016/07/13 PHP
PHP生成唯一ID之SnowFlake算法
2016/12/17 PHP
Laravel框架控制器,视图及模型操作图文详解
2019/12/04 PHP
php传值和传引用的区别点总结
2019/11/19 PHP
jQuery-ui引入后Vs2008的无智能提示问题解决方法
2014/02/10 Javascript
javascript常用的正则表达式实例
2014/05/15 Javascript
js实现的倒计时按钮实例
2015/06/24 Javascript
javascript实现支持移动设备画廊
2015/08/24 Javascript
js+CSS实现模拟华丽的select控件下拉菜单效果
2015/09/01 Javascript
JavaScript基本语法学习教程
2016/01/14 Javascript
node+express制作爬虫教程
2016/11/11 Javascript
JS中对数组元素进行增删改移的方法总结
2016/12/15 Javascript
微信小程序 增、删、改、查操作实例详解
2017/01/13 Javascript
移动设备手势事件库Touch.js使用详解
2017/08/18 Javascript
zTree异步加载展开第一级节点的实现方法
2017/09/05 Javascript
javascript+css3开发打气球小游戏完整代码
2017/11/28 Javascript
小程序云开发实现数据库异步操作同步化
2019/05/18 Javascript
在layui tab控件中载入外部html页面的方法
2019/09/04 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
2019/09/28 Javascript
JavaScript中变量提升机制示例详解
2019/12/27 Javascript
[03:54]Ehome出征西雅图 回顾2016国际邀请赛晋级之路
2016/08/02 DOTA
python多线程socket编程之多客户端接入
2017/09/12 Python
利用Python yagmail三行代码实现发送邮件
2018/05/11 Python
python退出循环的方法
2020/06/18 Python
CAT鞋加拿大官网:CAT Footwear加拿大
2020/08/05 全球购物
公司综合部的成员自我评价分享
2013/11/05 职场文书
行政总监岗位职责
2013/12/05 职场文书
顶撞老师检讨书
2014/02/07 职场文书
励志演讲稿3分钟
2014/08/21 职场文书
党支部三会一课计划
2014/09/24 职场文书
2016年秋季运动会通讯稿
2015/11/25 职场文书
写作技巧:怎样写好一份优秀工作总结?
2019/08/14 职场文书
Redis延迟队列和分布式延迟队列的简答实现
2021/05/13 Redis
MyBatis-Plus 批量插入数据的操作方法
2021/09/25 Java/Android