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

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

发表于2016/1/17 13:27:34  638人阅读

分类: JavaScript

先看看下面的程序:

var sum = 0;
for(var i = 0; i < 10; i++) {
  sum += 0.1;
}

console.log(sum);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

上面的程序会输出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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

数在计算机内部的表示

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

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

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

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

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

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

小数的二进制表示

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

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

二进制数 对应的十进制数
0.0000 0
0.0001 0.0625
0.0010 0.125
0.0011 0.1875
0.0100 0.25
0.1000 0.5
0.1001 0.5625
0.1010 0.625
0.1011 0.6875
0.1111 0.9375

从上表可以看出,十进制数 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…(无限循环)
  • 1
  • 2
  • 3
  • 4
  • 5

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

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

总结

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

时间: 2024-10-19 07:25:28

js为什么不能正确处理小数运算?的相关文章

JS操作小数运算,结果莫名其妙出现多位小数问题

Number类型: Number类型是ECMAScript中最常用和最令人关注的类型了:这种类型使用IEEE754格式来表示整数和浮点数值(浮点数值在某些语言中也被成为双精度数值),为支持各种数据类型,ECMA-262定义了不同的数值面量格式. 十进制: var intNum=10; //整数 八进制: var octalNum1=070; //八进制的56 var octalNum2=079; //无效的八进制数值-解析为79 八进制字面量在严格模式下是无效的: 十六进制: var hexNu

JS小数运算失精度的问题

浮点数值的最高精度是17位小数,但在进行运算的时候其精确度却远远不如整数:整数在进行运算的时候都会转成10进制: 而java和JavaScript中计算小数运算时,都会先将十进制的小数换算到对应的二进制,一部分小数并不能完整的换算为二进制,这里就出现了第一次的误差.待小数都换算为二进制后,再进行二进制间的运算,得到二进制结果.然后再将二进制结果换算为十进制,这里通常会出现第二次的误差. 所以(0.1+0.2)!=03 解决这种问题,可以将小数变成整数进行运算,然后再将结果变为小数. var ca

匹夫细说C#:妥协与取舍,解构C#中的小数运算

题外话 正文开始之前,我首先要感谢博客园提供的这个优秀的平台.通过在这个优秀的平台上和很多志同道合的朋友交流,互相帮助,我也很荣幸的获得了15年的微软MVP的奖项.也使我更加坚信了代码改变世界.感激!感恩!努力!加油! 0x00 前言 慕容在生活和工作中常常会遇到一些十分迷信机器的人,他们之中很多人都相信机器是最理智的,没有任何感情,是真正的铁面无私,因此机器的运算所给出的答案总是正确的,如果答案错误,那么一定是操作机器的人的问题.但机器的运算就一定是正确的吗?事实上,机器出现运算错误并不是一个

js如何实现数字保留小数点后两位小数

js如何实现数字保留小数点后两位小数:小数点后保留两位小数是比较常见的形式,由于比较简单,下面直接给出例子.代码如下: var num=3.1415926; console.log(num.toFixed(2)); toFixed()函数可以参阅javascript的Number对象的toFixed()方法一章节. 原文地址是:http://www.softwhy.com/forum.php?mod=viewthread&tid=9567 更多内容可以参阅:http://www.softwhy.

JS小数位保留两位小数

parseInt,parseFloat,parseDouble在JS中是将值转换成相应的类型: alert(parseFloat(12.44644).toFixed(2)); JS小数位保留两位小数,布布扣,bubuko.com

用于JS日期格式化,以及简单运算的Date包装工具类

1. [文件] yDate.js/** * | yDate.js | Copyright (c) 2013 yao.yl | email: [email protected] | Date: 2012-09-03 | */(function(global) {     var objectPrototypeToString = Object.prototype.toString;     var isDate = function(value) {        return objectPro

js转化 保留2位小数

//转换小数点格式为float 保留2位xiaoshu     function changeTwoDecimal_f(x) { var f_x = parseFloat(x); if (isNaN(f_x)) { alert('function:changeTwoDecimal->parameter error'); return false; } var f_x = Math.round(x * 100) / 100; var s_x = f_x.toString(); var pos_de

js校验数字是否为小数

js校验数字是否为小数: function checkDot(c) { var r= /^[1-9]?[0-9]*\.[0-9]*[1-9]+$/; return r.test(c); }

小数运算需要注意什么? 接口和抽象类 WinForm窗体上两个panel,怎么实现一个panel固定漂浮在另一个panel之上

小数运算需要注意什么? 1. 生活中0.1+0.2=0.3, 计算机中可不是这样,为什么呢? 大家都知道计算机类型都是有数据范围的.整形int范围是 正负21亿左右,小数类型同样也是有范围的,但是即使0.1~0.2之前如果问你有多少小数? 无穷个!!! 那么有限的范围怎么表示无限的数据呢? 告诉你表示不了,只能存储一个无限接近的数. 另外大家都知道计算机所有数据都是二进制,0.5即 2的-1次方,0.25是2的-2次方,同样解释了为什么不能表达所有小数. 这样大家也就明白下面这个例子 100个0