Appearance
Number 类型
Number 类型的存储
在 JavaScript 中 Numebr 类型遵循的是 IEEE 754 规范中的 64 位双精度浮点数(Java 的 Double 也是遵循此规范)。
IEEE 754 规范
小知识:
精度 | 符号位 | 指数位(阶符) | 尾数位 | 总位数 |
---|---|---|---|---|
单精度 | 1 | 8 | 23 | 32 |
双精度 | 1 | 11 | 52 | 64 |
长双精度 | 1 | 15 | 64 | 80 |
符号位: 0 :正数 1:负数
指数位:11 位指数 => -1023 - 1024( (1-2^10) 到 2^10)
为什么 11 位却是使用 2^10 的范围?
尾数: 52 位
1 的二进制码
js
// 二进制
1
// 符号位为 0 ,指数位为0
1.000000
// 移位到首位为1
1.000000 * 2^0 // 没有移位
// 符号位为 0 ; 指数位为 1023+0 => 01111111111 尾数位 : 00000000...
0 01111111111 000000000000(52位)
20.59375 的二进制码
js
20.59375
// 正数位
20 -> 10100
// 小数位 0.59375
0.59375 -> 10011
// 20.59375的二进制
10100.10011
// 符号位为 0 ,左偏移4位
1.010010011 * 2^4
// 符号位为 0 ; 指数位为 1023+4 => 10000000011 尾数位 : 010010011 00000...
0 10000000011 010010011000(52位)
// 结果为:
01000000 00110100 10011000 00000000 00000000 00000000 00000000 00000000
问题
- 精度问题
十进制转换成二进制的时候可能存在尾数多余 52 位的情况,那将尾数多余 52 位的部分舍去也就会导致精度不准确。
著名的栗子: 0.1 + 0.2 === 0.3 // ?
原因
js
// IEEE 754中 0.1的二进制为
存储格式 : 0 01111111011 1001100110011001100(1011*13)
转换成十进制: 0.000110011001(1001*11) => 0.09999999999999787
// 0.2
存储格式 : 0 01111111100 1001100110011001100
转换成十进制: 0.00110011001(1001*11) => 0.19999999999999574
parseInt()
parseInt(string, radix) 解析一个字符串并返回指定基数的十进制整数,radix 是 2-36 之间的整数,表示被解析字符串的基数。
语法
js
parseInt(string, radix)
参数
string 要被解析的值。如果参数不是一个字符串,则将其转换为字符串 (使用 ToString 抽象操作)。字符串开头的空白符将会被忽略。
radix 可选 从 2 到 36 的整数,表示进制的基数。例如指定 16 表示被解析值是十六进制数。如果超出这个范围,将返回 NaN。假如指定 0 或未指定,基数将会根据字符串的值进行推算。注意,推算的结果不会永远是默认值 10!文章后面的描述解释了当参数 radix 不传时该函数的具体行为。
返回值
从给定的字符串中解析出的一个整数。
或者 NaN,当
- radix 小于 2 或大于 36,或 字符串中第一个下标的值大于基数
js
parseInt("14", 1) // NaN 基数1小于2
parseInt("14", 100) // NaN 基数100大于36
parseInt("34", 2) // NaN 字符串中第一个下标的值大于基数 3>2
parseInt("34", 3) // 3 第二个字符 4 > 3; 所以结果就是 3*3^0
parseInt("212412", 3) // 23 第四个字符 4 > 3; 所以结果就是 2*3^2 + 1*3^1 + 2*3^0 = 23
- 第一个非空格字符不能转换为数字。
题目
["1","2","3"].map(parseInt)
的结果
拆分:
- parseInt的入参为两个 : string : 字符串值 , radix: 基数
- map 遍历的回调参数为3个 : value : 值 , index: 下标 , array: 原始数组
那么实际相当于
js
["1","2","3"].map((value , index) => parseInt(value , index))
// ===
[parseInt("1" , 0) , parseInt("2" , 1) , parseInt("3" , 2)]
// 第一个基数为0,那么就按照字符串默认基数处理,这边是10。 结果为 1
// 第二个基数为1,基数小于2; 结果为N
// 第三个基数为2, 3>2,转换失败; 结果为N
// 最终结果为 : [1 , NaN , NaN]
Number.parseInt
和parseInt
的区别