夯实基础-JS数字

173 阅读4分钟

前言

阅读 现代Javascript教程过程中记录了一些忽略的点,知其然知其所以然,温故而知新,文章分QA两部分,知道的同学可以直接划过。

Question

  • JS 对于数字是怎么存储的?
  • 如何判断一个数字是整数?
  • 最大安全数是多少?为什么?
  • JS 能表示的最大数字是多少?为什么?
  • 精度问题是怎么产生的?如何解决?
  • 转换数字都有哪几种方式?
  • NaN的比较怎么相等?
  • null>0?null==0?null>=0?
  • toFixed是怎么进行舍入的?
  • BigInt 可以被JSON化么?

Answer

JS 对于数字是怎么存储的?

JavaScript 中的常规数字以 64 位的格式 IEEE-754 存储,也被称为“双精度浮点数”。

比特长度:11152
名称:SExpFraction
比特编号:6362至52 偏正值(实际的指数大小+1023)51至0位编号(从右边开始为0)

ps:JS没有其他语言的 int,float,double 之分,存储结构全是64位的。

如何判断一个数字是整数?

Number.isInteger = Number.isInteger || function(value) {
    return typeof value === "number" &&
           isFinite(value) &&
           Math.floor(value) === value;
};

最大安全数是多少?为什么?

最大安全数是Number.MAX_SAFE_INTEGER,是一个值为 9007199254740991 的常量【2^53 - 1】。因为IEEE-754只有52位是用于尾数存储。

JS 能表示的最大数字是多少?为什么?

最大数字是Number.MAX_VALUE 约等于 1.7976931348623157 × 10^308。因为最大的话就是指数拉满,尾数拉满,其中尾数拉满就是最大安全数,但是需要注意尽管用11位表示指数位,但为了方便计算忽略正负的差异,实际上是有一个偏正值的【这样就全是正的了】所以指数拉满是 1023【2^10 - 1】。综上最大数字为 2^1023 * Number.MAX_SAFE_INTEGER

精度问题是怎么产生的?如何解决?

一个数字以其二进制的形式存储在内存中,一个 1 和 0 的序列。但是在十进制数字系统中看起来很简单的 0.10.2 这样的小数,实际上在二进制形式中是无限循环小数。使用二进制数字系统无法 精确 存储 0.1 或 0.2,就像没有办法将三分之一存储为十进制小数一样。

解决方案:

  • 将浮点数转为整数运算,再对结果做除法
  • 把浮点数转化为字符串,模拟实际运算的过程
  • 直接使用现成强大的库decimalnumber-precisionmathjs等【直接用第三方库吧,毕竟经历过大家检验的】

转换数字都有哪几种方式?

  • 一元 +
  • 显式调用 Number(xxx)
  • parseInt(string[, radix]) 转换为整数,转换算法是去除首尾空格,从前向后扫描,碰到第一个非数字相关字符停止扫描返回结果,如果第一个字符就和数字无关则返回 NaN
  • parseFloat(string)parseInt几乎一致,但是缺少第二个基数可选参数

ps: 一元 +运算转换不了 BigInt 类型,Number() 则可以

NaN 的比较怎么相等?

NaN == NaN 为 false,而 Object.is(NaN,NaN)true。这是 Object.is=== 区别之一,还有一点不同是对于 +0 和 -0 的比较对待,Object.is 视为 false,而 === 视为 true

ps:在 Map 数据结构中用NaN的比较算法是Object.is

null>0?null==0?null>=0?

alert( null > 0 );  // (1) false 
alert( null == 0 ); // (2) false 
alert( null >= 0 ); // (3) true

因为相等性检查 == 和普通比较符 > < >= <= 的代码逻辑是相互独立的。进行值的比较时,null 会被转化为数字,因此它被转化为了 0。这就是为什么(3)中 null >= 0 返回值是 true,(1)中 null > 0 返回值是 false。

另一方面,undefined 和 null 在相等性检查 == 中不会进行任何的类型转换,它们有自己独立的比较规则,所以除了它们之间互等外,不会等于任何其他的值。这就解释了为什么(2)中 null == 0 会返回 false。

toFixed 是怎么进行舍入的?

很多人说是银行家算法,但是并不是银行家算法四舍六入五取偶(又称四舍六入五留双)

具体查看规范【英文版】:262.ecma-international.org/6.0/#sec-nu…

规范【中文版】:yanhaijing.com/es5/#429

toFixed.png

这里有个很有意思的题为什么 6.35.toFixed(1) == 6.3?

根据规范公示去算的话 保留一位小数 要么6.3 要么6.4,这和6.35减下来都是0.05,照规范应该选大的6.4啊,为啥最后会是6.3呢?【用计算机算,不要用人算你就知道咋回事了,是精度造成的】

63/10 - 6.35 // -0.04999999999999982
64/10 - 6.35 // 0.05000000000000071

BigInt 可以被JSON化么?

不能

参考: