[TOC] # **Number数值类型** **表示方式** &emsp;&emsp;JavaScript 中的数字类型只有 Number 一种,Number 类型采用 IEEE754 标准中的 “双精度浮点数” 来表示一个数字,不区分整数和浮点数 。 <br> ## **1、存储结构** &emsp;&emsp;在 IEEE754 中,双精度浮点数采用 64 位存储,即 8 个字节表示一个浮点数 。其存储结构如下图所示: ![](https://images2017.cnblogs.com/blog/849589/201710/849589-20171013113026887-1981568120.png) <br> &emsp;&emsp;指数位可以通过下面的方法转换为使用的指数值: ![](https://images2017.cnblogs.com/blog/849589/201710/849589-20171013112848699-2046443732.png) <br> ## **2 、数值范围** &emsp;&emsp;从存储结构中可以看出, 指数部分的长度是11个二进制,即指数部分能表示的最大值是 2047(211\-1),取中间值进行偏移,用来表示负指数,也就是说指数的范围是 \[-1023,1024\] 。因此,这种存储结构能够表示的数值范围为 21024 到 2\-1023 ,超出这个范围的数无法表示 。21024 和 2\-1023  转换为科学计数法如下所示: >[success]1.7976931348623157 × 10308 > >5 × 10\-324 &emsp;&emsp;因此,JavaScript 中能表示的最大值是 **1.7976931348623157 × 10308**,最小值为 **5 × 10\-324**。 这两个边界值可以分别通过访问 Number 对象的 MAX\_VALUE 属性和 MIN\_VALUE 属性来获取: >[success]Number.MAX_VALUE;// 1.7976931348623157e+308 > Number.MIN_VALUE;// 5e-324 &emsp;&emsp;如果数字超过最大值或最小值,JavaScript 将返回一个不正确的值,这称为 “**正向溢出(overflow)**” 或 “**负向溢出(underflow)**” 。  >[success]12345Number.MAX_VALUE+1 == Number.MAX_VALUE;//trueNumber.MAX_VALUE+1e292;//InfinityNumber.MIN_VALUE + 1;//1Number.MIN_VALUE - 3e-324;//0Number.MIN_VALUE - 2e-324;//5e-324 <br> ## **3、 数值精度** &emsp;&emsp;在 64 位的二进制中,符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。 &emsp;&emsp;IEEE754 规定,有效数字第一位默认总是1 。因此,在表示精度的位数前面,还存在一个 “隐藏位” ,固定为 1 ,但它不保存在 64 位浮点数之中。也就是说,有效数字总是 1.xx...xx 的形式,其中 xx..xx 的部分保存在 64 位浮点数之中,最长为52位 。所以,JavaScript 提供的有效数字最长为 53 个二进制位,其内部实际的表现形式为: >[success](-1)^符号位 \* 1.xx...xx \* 2^指数位 &emsp;&emsp;这意味着,JavaScript 能表示并进行精确算术运算的整数范围为:\[-253\-1,253\-1\],即从最小值 -9007199254740991 到最大值 9007199254740991 之间的范围 。 ``` Math.pow(2, 53)-1 ;// 9007199254740991 -Math.pow(2, 53)-1 ;// -9007199254740991 ``` 可以通过 Number.MAX\_SAFE\_INTEGER 和  Number.MIN\_SAFE\_INTEGER 来分别获取这个最大值和最小值。  ``` console.log(Number.MAX_SAFE_INTEGER) ;// 9007199254740991 console.log(Number.MIN_SAFE_INTEGER) ;// -9007199254740991 ``` 对于超过这个范围的整数,JavaScript 依旧可以进行运算,但却不保证运算结果的精度。 ``` Math.pow(2, 53) ;// 9007199254740992 Math.pow(2, 53) + 1;//9007199254740992 9007199254740993;//9007199254740992 90071992547409921;//90071992547409920 0.923456789012345678;//0.9234567890123456 ``` <br> ## **4、 精度丢失** &emsp;&emsp;计算机中的数字都是以二进制存储的,如果要计算 0.1 + 0.2 的结果,计算机会先把 0.1 和 0.2 分别转化成二进制,然后相加,最后再把相加得到的结果转为十进制 。 &emsp;&emsp;但有一些浮点数在转化为二进制时,会出现无限循环 。比如, 十进制的 0.1 转化为二进制,会得到如下结果: >[success] 0.0001 1001 1001 1001 1001 1001 1001 1001 …(1001无限循环) &emsp;&emsp;而存储结构中的尾数部分最多只能表示 53 位。为了能表示 0.1,只能模仿十进制进行四舍五入了,但二进制只有 0 和 1 , 于是变为 0 舍 1 入 。 因此,0.1 在计算机里的二进制表示形式如下: >[success] 0.0001100110011001100110011001100110011001100110011001101 &emsp;&emsp;用标准计数法表示如下: >[success] (−1)0 × 2−4× (1.1001100110011001100110011001100110011001100110011010)2 &emsp;&emsp;同样,0.2 的二进制也可以表示为:  >[success] (−1)0 × 2−3 × (1.1001100110011001100110011001100110011001100110011010)2  &emsp;&emsp;在计算浮点数相加时,需要先进行 “对位”,将较小的指数化为较大的指数,并将小数部分相应右移: >[success] 0.1→ (−1)0 × 2−3 × (0.11001100110011001100110011001100110011001100110011010)2 > 0.2→ (−1)0 × 2−3 × (1.1001100110011001100110011001100110011001100110011010)2 &emsp;&emsp;最终,“0.1 + 0.2” 在计算机里的计算过程如下: ![](https://images2017.cnblogs.com/blog/849589/201710/849589-20171013113341277-1573319144.png) &emsp;&emsp;经过上面的计算过程,0.1 + 0.2 得到的结果也可以表示为: >[success] (−1)0 × 2−2 × (1.0011001100110011001100110011001100110011001100110100)2 &emsp;&emsp;然后,通过 JS 将这个二进制结果转化为十进制表示: >[success] 12(-1)**0 * 2**-2 * (0b10011001100110011001100110011001100110011001100110100 * 2**-52);//0.30000000000000004console.log(0.1 + 0.2) ;// 0.30000000000000004 &emsp;&emsp;这是一个典型的精度丢失案例,从上面的计算过程可以看出,0.1 和 0.2 在转换为二进制时就发生了一次精度丢失,而对于计算后的二进制又有一次精度丢失 。因此,得到的结果是不准确的。 <br> ## **5、 特殊数值** JavaScript 提供了几个特殊数值,用于判断数字的边界和其他特性 。如下所示: * Number.MAX\_VALUE:JavaScript 中的最大值 * Number.MIN\_VALUE:JavaScript 中的最小值 * Number.MAX\_SAFE\_INTEGER:最大安全整数,为 253\-1 * Number.MIN\_SAFE\_INTEGER:最小安全整数,为 -(253\-1) * Number.POSITIVE\_INFINITY:对应 Infinity,代表正无穷 * Number.NEGATIVE\_INFINITY:对应 -Infinity,代表负无穷 * Number.EPSILON:是一个极小的值,用于检测计算结果是否在误差范围内 * Number.NaN:表示非数字,NaN与任何值都不相等,包括NaN本身 * Infinity:表示无穷大,分 正无穷 Infinity 和 负无穷 -Infinity <br> ## **6 、数值转换** 有 3 个函数可以把非数值转换为数值,分别如下: ``` Number(value) parseInt(string [, radix]) parseFloat(string) ``` &emsp;&emsp;Number() 可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。 &emsp;&emsp;对于字符串而言,Number() 只能对字符串进行整体转换,而 parseInt() 和 parseFloat() 可以对字符串进行部分转换,即只转换第一个无效字符之前的字符。 对于不同数据类型的转换,Number() 的处理也不尽相同,其转换规则如下: 【1】如果是 Boolean 值,true 和 false 将分别被转换为 1 和 0。  【2】如果是数字值,只是简单的传入和返回。 【3】如果是 null 值,返回 0。 【4】如果是 undefined,返回 NaN。 【5】如果是字符串,遵循下列规则: * 如果字符串中只包含数字(包括前面带正号或负号的情况),则将其转换为十进制数值;  * 如果字符串中包含有效的浮点格式,则将其转换为对应的浮点数值;  * 如果字符串中包含有效的十六进制格式,则将其转换为相同大小的十进制整数值;  * 如果字符串是空的(不包含任何字符),则将其转换为 0;  * 如果字符串中包含除上述格式之外的字符,则将其转换为 NaN。 【6】如果是对象,则调用对象的 valueOf() 方法,然后依照前面的规则转换返回的值。如果转换的结果是 NaN,则调用对象的 toString() 方法,然后再次依照前面的规则转换返回的字符串值。 需要注意的是: >[success]一元加操作符加号 “+” 和 Number() 具有同样的作用。 &emsp;&emsp;在 ECMAScript 2015 规范中,为了实现全局模块化,Number 对象重写了 parseInt 和 parseFloat 方法,但和对应的全局方法并无区别。 12Number.parseInt === parseInt;// trueNumber.parseFloat === parseFloat;// true <br> ## **7 、位运算** &emsp;&emsp;位运算作用于最基本的层次上,即按内存中表示数值的位来操作数值。ECMAScript 中的数值以64位双精度浮点数存储,但位运算只能作用于整数,因此要先将 64 位的浮点数转换成 32 位的整数,然后再进行位运算,最后再将计算结果转换成64位浮点数存储。常见的位运算有以下几种: * 按位非(NOT):~  * 按位与(AND):&  * 按位或(OR): | * 按位异或(XOR):^ * 左移:<< * 有符号右移:>>  * 无符号右移:>>> 需要注意的是: >[success] “有符号右移” 和 “无符号右移” 只在计算负数的情况下存在差异,>> 在符号位的右侧补0,不移动符号位;而 >>> 是在符号位的左侧补0,符号位发生移动和改变。 <br> ## **8、 四舍五入** &emsp;&emsp;JavaScript 对数字进行四舍五入操作的 API 有 ceil,floor,round,toFixed,toPrecision 等,详细介绍请参考:[JavaScript 中的四舍五入]&emsp;http://www.cnblogs.com/onepixel/p/5141566.html