0.1+0.2!=0.3

175 阅读2分钟

内容概要

  • 十进制转换为二进制的计算 n.toString(2)
    • 整数部分
    • 小数部分
  • JS使用Number类 型表示数字(整数和浮点数),遵循IEEE-754标准通过 64位二进制值来表示一个数字 babbage.cs.qc.cuny.edu/IEEE-754.ol…
    • 第0位: 符号位,0表示正数,1表示负数 S
    • 第1位到第11位「11位指数」: 储存指数部分 E
    • 第12位到第63位「52位尾数」:储存小数部分(即有效数字) F
    • 注:尾数部分在规约形式下第一位默认为1 (省略不写)
  • 最大安全数字「16位」Number.MAX_ SAFE_ INTEGER === Math.pow(2,53)-1
  • 怎么解决精度问题?
    • 将数字转成整数「扩大系数」
    • 第三方库: Math.js 、decimal.js、 big.js ...

0.1+0.2!=0.3

  • JS中有关小数(浮点数)的计算会出现精准度丢失的问题
    • JS中所有的值都是以2进制在计算机底层进行存储的{浮点数转换为二进制,可能出现无限循环的情况}
    • 在计算机底层存储的时候,最多存储64位【舍弃了一些值,值本身就失去了精准度】
  • 浮点数计算的解决方案
    • toFixed 保留小点后面的N位,他自己会四舍五入
    • 扩大系数法
// 求系数
const coefficient = function coefficient(num) {
  num = num + '';
  let [, char = ''] = num.split('.'),
    len = char.length;
  return Math.pow(10, len) //-> 10**len
}
const plus = function plus(num1, num2) {
  num1 = +num1;
  num2 = +num2;
  if (isNaN(num1) || isNaN(num2)) return NaN // 非有效数字
  let max = Math.max(coefficient(num1), coefficient(num2));
  return (num1 * max + num2 * max) / max
}

console.log(plus(0.1, 0.2))
console.log(plus(0.1, 0.2123))

==和对象转数字的应用

== 涉及到比较的时候数据类型的转化,如果a是对象比较时会把a转为数字再进行比较 对象转为数字, 先看是否有Symbol.toPrimitive,如果这个方法不存在,
用valueOf()返回是否是原始值,如果不是,
用toString(),转为字符串,
再用Number()转为数字,
重写Symbol.toPrimitive,valueOf(),toString()都可以

// 方法一:
var a = {
  i: 0,
  [Symbol.toPrimitive]() {
    return ++this.i
  }
}
if (a == 1 && a == 2 && a == 3) {
  console.log('OK')
}

// 方法二:
var a = [1, 2, 3];
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
  console.log('OK')
}

// 方法三: 全局上下文中,获取a的值:首先看VO(G)中有没有,没有再继续去GO(window)中查找
var i = 0;
Object.defineProperty(window, 'a', {
  get() {
    return ++i;
  }
})
if (a == 1 && a == 2 && a == 3) {
  console.log('OK')
}