js之数字

332 阅读7分钟

1、js中最大数字和最小数字:

Number.MAX_VALUE: 1.7976931348623157e+308
Number.MIN_VALUE: 5e-324

Number.MAX_SAFE_INTEGER: 9007199254740991
Number.MIN_SAFE_INTEGER: -9007199254740991

易推出 Javascript 能表示的最大数Number.MAX_VALUE:

1*(Math.pow(2, 53) - 1) * Math.pow(2, 971) = 1.7976931348623157e+308

同理可推得 Number.MIN_VALUE 的值:

1 * 1 * Math.pow(2, -1074) = 5e-324

需要注意的是,Number.MIN_VALUE 表示的是最小的比零大的数,而不是最小的数,最小的数很显然是 -Number.MAX_VALUE。

2、为什么 0.1+0.2 = 0.30000000000000004

十进制转二进制

  • 整数部分 "除二取余,倒序排列"
  • 小数部分 "乘二取整,顺序排列"
0.1*2=0.2  //0
0.2*2=0.4 //0
0.4*2=0.8 //0
0.8*2=1.6 //1
0.6*2=1.2 //1
0.2*2=0.4 //0

0.2*2=0.4 //0
0.4*2=0.8 //0
0.8*2=1.6 //1
0.6*2=1.2 //1
0.2*2=0.4 //0

0.1的二进制:0.000110011......0011......(0011无限循环)
0.2的二进制:0.00110011......0011...... (0011无限循环)

浮点数科学计数法

根据IEEE 754标准,任意一个浮点数的二进制都可以用如下公式进行表示:

说明:E是无符号整数,长度是11位,取值范围是为0~2047。因为科学计数法中的指数是可以为负数,所以约定减去一个中间数(偏移量)1023,[0,1022] 表示为负,[1024,2047] 表示为正。

e = -4; m =1.1001100110011001100110011001100110011001100110011010 (52位)
e = -3; m =1.1001100110011001100110011001100110011001100110011010 (52位)

0.1的小数点向右移动4位,让其小数点左边只有一个“1”。0.2的小数点向右移动4位,让其小数点左边只有一个“1”。根据IEEE 754标准,双精度浮点的尾数只能存储52位,最后的“1”是第53位,根据进1舍0的原则进行操作。

二进制存储格式

  e = -4; m = 1.1001100110011001100110011001100110011001100110011010 (52位)
+ e = -3; m = 1.1001100110011001100110011001100110011001100110011010 (52位)
-----------------------------------------------------------------
相加时如果指数不一致,需要对齐,根据小阶向大阶看齐的原则,一般情况下是向右移,因为最右边的即使溢出了,损失的精度远远小于左边溢出。
  e = -3; m = 0.1100110011001100110011001100110011001100110011001101 
+ e = -3; m = 1.1001100110011001100110011001100110011001100110011010
-----------------------------------------------------------------
  e = -3; m = 10.0110011001100110011001100110011001100110011001100111
规格化
-----------------------------------------------------------------
  e = -2; m = 1.0011001100110011001100110011001100110011001100110100(52位)
-----------------------------------------------------------------
= 0.010011001100110011001100110011001100110011001100110100
= 0.3000000000000000444089209850062616169452667236328125
= 0.30000000000000004(十进制)

浮点数存储格式

上图是64位的双精度浮点数,

  • 最高位是符号位S(sign),表示浮点数的正负(0代表正数,1代表负数)
  • 中间的11位是指数E(exponent),该数都会加上一个常数(偏移量),用来表示次方数;
  • 剩下的52位为尾数(有效数字)M(mantissa),表示有效位(尾数),超出的部分自动进1舍0

当结果大于 Math.pow(2, 53) 时,会出现精度丢失,导致最终结果存在偏差,而当结果大于 Number.MAX_VALUE,直接返回 Infinity。

3、位运算符

  • <<左移,符号位始终不变,空出位补0操作,超过32位自动丢弃。
  • >>有符号右移,把32位数字中的所有有效位整体右移,空出位置使用符号位填补,超出32位被丢弃
  • >>>无符号右移,把无符号的32位整数所有数位整体右移,使用0来填充所有的空位
  • &按位与;|按位或;^按位异或;~按位反
0 (base 10) = 00000000000000000000000000000000 (base 2)
-1 (base 10) = 11111111111111111111111111111111 (base 2)
-2147483648 (base 10) = 10000000000000000000000000000000 (base 2) 
2147483647 (base 10) = 01111111111111111111111111111111 (base 2)

32位有符号数字的最小负整数为-2147483648,最大整数为2147483647即(2^31-1)

314的二进制编码:

00000000000000000000000100111010

编码~314,即 314

11111111111111111111111011000101

314 的反码再加1,得到编码 -314,即

11111111111111111111111011000110

补码形式是指一个数的负对应值(如 5和-5)为数值的所有比特位反转后,再加1。补码保证了当一个数是正数时,其最左的比特位是0,当一个数是负数时,其最左的比特位是1。

1、js按位运算时,小数部分怎么处理呢?答案是直接丢弃

~~2.8 //2
~~-2.8  //2

2、js的非数值类型如何进行位运算的呢?

当 js 需要进行位运算的时候,对于非数值类型,会首先将操作数转成一个整型(就是0)然后在进行运算。这就解释了为什么 js 中可以允许非数值类型参与运算,其实这是个伪命题,因为实质上是对非数值操作数的整型表达式进行的位运算。

所以对一个非数值变量做取反操作,得到的一定是 -1,因为实际上等于对 0 做取反操作

~0 == -1
~NaN == -1
~null == -1
~'xx' == -1
~[] == -1
~{} == -1
~func == -1
function func(){}

3、js中的无符号右移(>>>)到底有什么特别之处?

那就是并没有真正发生移位的情况下,符号位会不会被替换成0,在js 中是会发生替换的。

//当操作数是负数时,移动位数大于0,也体现不出区别
1>>>0 //1
-1>>>1 //2147483647
//但是当操作数是负数,无符号右移 0 位时,区别就大了
-1 >>> 0 // 4294967295

-1 (base 10) = 11111111111111111111111111111111 (base 2)

-1的补码为

11111111111111111111111111111111

>>>0 实际上并没有发生数位变化,但是 js 却会把符号位替换成 0

01111111111111111111111111111111

js 中无符号右移时,不管正数、负数都会首先将符号位替换成 0,然后再进行移位。也就是说,该运算符永远返回正整数。

4、~~与Math.floor的区别 ~是按位取反,两次取反后变回原来的操作数。但是当操作数是小数的时候,会忽略其小数部分

~~43.2 == (~)~43.2 == ~(~43.2) == 43
~~-43.2 == ~(~-43.2) == -43

Math.floor(43.2) == 43
Math.floor(-43.2) == -44

5、按位运算的应用有哪些?

(1)奇偶判断

数字 & 1 = 1奇数
数字 & 1 = 0偶数

(2)取整

 ~~2.83 //2
 2.83 >> 0 //2
 2.83 << 0 //2
 2.83 | 0 //2

(3)计算乘除

//左移一位相当于乘2,左移n位相当于乘以2的n次方
5 << 3 //5*(2^3)=40

//右移一位相当于除2,右移n位相当于除以2的n次方
5 >> 3 //5/(2^3)=0
-5 >> 3 //-1

(4)判断两个整数是否相等

//异或
3 ^ 5 != 0
5 ^ 5 = 0

(5)交互两个整数

function swap(num1, num2){
	num1 = num1 ^ num2;
    num2 = num1 ^ num2;
    num1 = num1 ^ num2;
}

(6)rgb与16进制颜色直接的转换

function hexToRGB(hex){
    hex = hex.replace('#', '0x');
    const r = hex >> 16;
    const g = hex >> 8 & 0xff;
    const b = hex & 0xff;
    console.log(`rgb(${r}, ${g}, ${b})`);
}
function RGBToHex(rgb){
    const rgbArr = rgb.split(/[^\d]+/);
    const color = rgbArr[1] << 16 | rgbArr[2] << 8 | rgbArr[3];
    return '#' + color.toString(16);
}

4、二进制、十进制、八进制、十六进制之间的转换

其他进制转十进制:Number.parseInt(string , radix)

//字符串转数字
var str = '1100';
parseInt(str, 10);   //1100
parseInt(str, 2);    //12
parseInt(str, 8);    //576
parseInt(str, 16);  //4352

十进制转其他进制:Number.toString(radix)

//数字转字符串
var num = 12;
num.toString(10); //12
num.toString(2);  //1100
num.toString(8); //14
num.toString(16); //c

(0.1).toString(2); 
//"0.0001100110011001100110011001100110011001100110011001101"

二进制转八进制:parseInt(string, radix1).toString(radix1)

//使用十进制进行过度
parseInt('1100', 2).toString(8); //14

参考