JavaScript 系列 - number

229 阅读4分钟
typeof instance === "number"

进制

  • 0X、0x 十六进制
  • 0O、0o 八进制
  • 0B、0b 二进制格式
    • 莱布尼茨

分隔符

允许 JavaScript 的数值使用下划线(_)作为分隔符

  • 不能放在数字的最前面或最后面

  • 不能两个或两个以上的分隔符连在一起

  • 小数点的前后不能有分隔符

  • 科学计数法里面,表示指数的 e 或 E 前后不能有分隔符

  • 分隔符不能紧跟着进制的前缀 0b0B0o0O0x0X

  • 字符串转成数值的函数,不支持数值分隔符

    Number()
    parseInt()
    parseFloat()
    

十进制转为二进制

  • 正整数

    进制除二取余直到商为 0,然后倒序排列,高位补零

    十进制转为二进制

  • 负整数

    对应的正整数转换成二进制后,对二进制取反,然后对结果再加一

  • 计算机位数

    8 位、16位、32位、64 位

  • 小数转换为二进制

    • 对小数点以后的数乘以 2

    • 取结果的整数部分

    • 小数部分再乘以 2

    • 取结果的整数部分

    • 直到小数部分为 0 或者位数

    • 0.1 一直循环

      按要求保留足够位数的小数,最后一位 0 舍 1 入

十进制二进制 32 位精度换算

let bytes = new Float64Array(1);// 64位浮点数
bytes[0] = 0.1;// 填充0.1进去
let view = new DataView(bytes.buffer);
console.log(view.getUint8(0).toString(2));// 10011010

整数

  • Number.MAX_SAFE_INTEGER
  • Number.MIN_SAFE_INTEGER
  • 在这个范围内的整数转化为二进制存储的时候不会出现精度丢失

浮点数

双精度浮点数由三个部分组成,符号位、指数位与尾数位

二进制表示法.png

  • 不要使用浮点数进行循环课可能造成死循环

  • IEEE 754 双精度浮点数

  • JS 浮点数是 64 位双精度浮点数

  • 二进制浮点数, (-1)^s 表示符号位,当 s=0,V 为正数;当 s=1 V 为负数

  • 2^E 表示指数位

    • 加上一个中间数为真实值
      • 32 位精度,E 为 8 位数字
        • 127
        • 0-255
      • 64 位精度,E 为 11 位数字
        • 1023
        • 0-2047
    • E 不全为 0 或不全为 1
    • E 全为 0
      • E 等于 1-127(或者1-1023) -126 -1022
      • 有效数字 M 不再加上第一位的1
        • 还原为 0.xxxxxx 的小数
    • E 全为 1
      • 有效数字 M 全为 0,表示 ± 无穷大(正负取决于符号位 s)
      • 如果有效数字 M 不全为 0,表示这个数不是一个数(NaN)
    • 移位存储
  • M 表示有效数字,大于等于 1,小于 2

    • 默认舍去 1,只保存后面小数部分
  • 32 位的浮点数

    • 最高的 1 位是符号位 s,接着的 8 位是指数 E,剩下的 23 位为有效数字 M

    32位浮点数.png

  • 64 位的浮点数

    • 最高的 1 位是符号位 S,接着的 11 位是指数 E,剩下的 52 位为有效数字 M

    64位浮点数.png

IEEE 754 双精度浮点数内部表示法

原码

  • 最高位表示符号位,其余位表示数值位
  • 不能直接参与运算

反码

  • 正数的反码和其原码一样
  • 负数的反码,符号位为1,数值部分按原码取反

补码

  • 正数的补码和其原码一样
  • 负数的补码为其反码加1
  • 数据在计算机中主要是以补码的形式存储的

NaN

  • typeof NaN === "number"

  • NaN !== NaN

  • isNaN 和 Number.isNaN

    • Number.isNaN 如果参数类型不是NaN,一律返回false
    • isNaN 先调用Number()将非数值的值转为数值,再进行判断

parseInt 和 parseFloat

ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,行为完全保持不变。

Number.isInteger()

Number.isInteger()用来判断一个数值是否为整数。

Number.EPSILON

Number.EPSILON === Math.pow(2, -52)

JavaScript 能够表示的最小精度,误差如果小于这个值相当于不存在误差了。

function withinErrorMargin (left, right) {
  return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}

0.1 + 0.2 === 0.3 // false
withinErrorMargin(0.1 + 0.2, 0.3) // true

1.1 + 1.3 === 2.4 // false
withinErrorMargin(1.1 + 1.3, 2.4) // true

Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER

JavaScript 能够准确表示的整数范围在 -2^532^53 之间(不含两个端点),超过这个范围,无法精确表示这个值。

function trusty (left, right, result) {
  if (
    Number.isSafeInteger(left) &&
    Number.isSafeInteger(right) &&
    Number.isSafeInteger(result)
  ) {
    return result;
  }
  throw new RangeError('Operation cannot be trusted!');
}

trusty(9007199254740993, 990, 9007199254740993 - 990)
// RangeError: Operation cannot be trusted!

trusty(1, 2, 3)
// 3

添加货币分割符号

  • number.toLocaleString(['en'])

    function format(number) {
      return number.toLocaleString("en");
    }
    
  • Intl.NumberFormat().format(number)

    function format(number) {
      return Intl.NumberFormat().format(number);
    }
    
  • 使用正则表达进行替换

    function format(number) {
      const reg =
        number.toString().indexOf(".") > -1
          ? /(\d)(?=(\d{3})+\.)/g
          : /(\d)(?=(\d{3})+$)/g;
      return number.toString().replace(reg, "$1,");
    }
    

随机数

生成 [0, 1) 范围内的随机数

console.log(Math.random());

取得 [n, m] 范围随机数

function fullClose(n, m) {
  var result = Math.random() * (m + 1 - n) + n;
  while (result > m) {
    result = Math.random() * (m + 1 - n) + n;
  }
  return result;
}

取得 (n,m) 范围随机数

function fullOpen(n, m) {
  var result = Math.random() * (m - n) + n;
  while (result == n) {
    result = Math.random() * (m - n) + n;
  }
  return result;
}

取得 (n,m] 范围随机数

function leftOpen(n, m) {
  var result = Math.random() * (m - n + 1) + n - 1;
  while (result < n) {
    result = Math.random() * (m - n + 1) + n - 1;
  }
  return result;
}

取得 [n,m) 范围随机数

function rightOpen(n, m) {
  return Math.random() * (m - n) + n;
}

随机整数的生成

随机生成 0、1 这两个整数

Math.round(Math.random());

生成 [0, n) 范围内的随机整数

Math.floor(Math.random() * n);

生成 [1, n] 范围内的随机整数

Math.floor(Math.random() * n) + 1;

生成 [min, max] 范围内的随机整数

Math.floor(Math.random() * (max - min + 1)) + min;

生成 [min,max) 范围内的随机整数

Math.floor(Math.random() * (max - min) + min);

随机字符串的生成

生成 n 位数字字符串

function randomNum(n) {
  var res = "";
  for (var i = 0; i < n; i++) {
    res += Math.floor(Math.random() * 10);
  }
  return res;
}

生成 n 位数字字母混合字符串

function generateMixed(n) {
  var chars = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
  var res = "";
  for (var i = 0; i < n; i++) {
    var id = Math.floor(Math.random() * 36);
    res += chars[id];
  }
  return res;
}

其他值转化为数字

number

八进制作为十进制小数

string

NaN/0

var s = "123";
var n = Number(s);
var n = +s;
var n = Math.floor(n);
var n = ~~n;
var n = n | 0;

解析

var s = "123px";
var n = Number(s); // NaN
var n = parseInt(s); // 123
parseInt(1 / 0, 19); // 18
parseInt(Infinity, 19);
parseInt("I",19);

true

  • true => 1
  • false => 0

undefined

undefined => NaN

null

null => 0

object

  • ToPrimitive valueOf() 返回基本类型 基本类型转化为数字
  • toString() TypeError

Symbol

错误

bigInt

隐式错误

日期

var n = +new Date();

Math

  • Math.round() 四舍五入
  • Math.ceil() 向上取整
  • Math.floor() 向下取整