JavaScript常用进制转换及位运算实例解析
前言
在一般的代码中很少会接触到进制和位运算,但这不代表我们可以不去学习它。作为一位编程人员,这些都是基础知识。如果你没有学过这方面的知识,也不要慌,接下来的知识并不会很难。本文你将会学习到:
- 进制转换
- 按位操作符
- JavaScript进制转换
- 手动实现进制转换
进制转换
以下使用常见的十进制和二进制转换作为例子,其他进制的转换也是大同小异,感兴趣可以自己琢磨下。
十进制转二进制
根据“逢十进一”的法则进行计数时,每十个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做十进制计数法,简称十进制。这种是我们最常用的计数法。
整数
整数使用“除二取余,逆序排列”来转换为二进制,下面是18转换为二进制的例子:
//除二取余
18/2=9...0
9/2=4...1
4/2=2...0
2/2=1...0
1/2=0...1//倒序排列
10010
就这么简单,将得出的余数逆序排列,即可得出18的二进制表示
小数
小数使用的是“乘二取整,顺序排列”,由于方法不同需要分开计算。下面是16.125转为二进制的例子:
16/2=8...0
8/2=4...0
4/2=2...0
2/2=1...0
1/2=0...10.125*2=0.25
0.25*2=0.5
0.5*2=110000.001
将小数相乘的结果,取结果的整数顺序排列,得出小数位的二进制表示
二进制转十进制
根据“逢二进一”的法则进行计数时,每两个相同的单位组成一个和它相邻的较高的单位,这种计数法叫做二进制计数法,简称二进制。用二进制计数时,只需用两个独立的符号“0”和“1”来表示。
整数
整数使用“按权相加”法,即二进制数首先写成加权系数展开式,然后按十进制加法规则求和。下面是101010转换位十进制的例子:
2^52^42^32^22^12^0
101010
------------------------
32+0+8+0+2+0=42
上面从右数依次是2的0次方,2的1次方,2的2次方...,只取位数为1的结果,将它们相加就可以得到十进制。
小数
10110.11转十进制:
2^42^32^22^12^02^-12^-2
10110.11
-------------------------------
16+0+4+2+0+0.5+0.25=22.75
按位操作符
按位操作符(Bitwiseoperators)将其操作数(operands)当作32位的比特序列(由0和1组成),前31位表示整数的数值,第32位表示整数的符号,0表示正数,1表示负数。例如,十进制数18,用二进制表示则为10010。按位操作符操作数字的二进制形式,但是返回值依然是标准的JavaScript数值。
按位与(AND)
对于每一个比特位,只有两个操作数相应的比特位都是1时,结果才为1,否则为0。
用法:a&b。
9(base10)=00000000000000000000000000001001(base2)
14(base10)=00000000000000000000000000001110(base2)
--------------------------------
14&9(base10)=00000000000000000000000000001000(base2)=8(base10)
在判断一个数字奇偶时,可以使用a&1
functionassert(n){
returnn&1?"奇数":"偶数"
}
assert(3)//奇数
因为奇数的二进制最后一位是1,而1的二进制最后一位也是1,通过&操作符得出结果为1
按位或(OR)
对于每一个比特位,当两个操作数相应的比特位至少有一个1时,结果为1,否则为0。
用法:a|b
9(base10)=00000000000000000000000000001001(base2)
14(base10)=00000000000000000000000000001110(base2)
--------------------------------
14|9(base10)=00000000000000000000000000001111(base2)=15(base10)
将浮点数向下取整转为整数,可以使用a|0
12.1|0//12
12.9|0//12
按位异或(XOR)
对于每一个比特位,当两个操作数相应的比特位有且只有一个1时,结果为1,否则为0。
用法:a^b
9(base10)=00000000000000000000000000001001(base2)
14(base10)=00000000000000000000000000001110(base2)
--------------------------------
14^9(base10)=00000000000000000000000000000111(base2)=7(base10)
按位非(NOT)
反转操作数的比特位,即0变成1,1变成0。
用法:~a
9(base10)=00000000000000000000000000001001(base2)
--------------------------------
~9(base10)=11111111111111111111111111110110(base2)=-10(base10)
通过两次反转操作,可将浮点数向下取整转为整数
~~16.125//16
~~16.725//16
左移(Leftshift)
将a的二进制形式向左移b(<32)比特位,右边用0填充。 9(base10):00000000000000000000000000001001(base2)
用法:a<
--------------------------------
9<<2(base10):00000000000000000000000000100100(base2)=36(base10)
左移一位相当于在原数字基础上乘2,利用这一特点,实现2的n次方:
functionpower(n){
return1<}
power(3)//8
有符号右移
将a的二进制表示向右移b(<32)位,丢弃被移出的位。
用法:a>>b
9(base10):00000000000000000000000000001001(base2)
--------------------------------
9>>2(base10):00000000000000000000000000000010(base2)=2(base10)
相比之下,-9>>2得到-3,因为符号被保留了。
-9(base10):11111111111111111111111111110111(base2)
--------------------------------
-9>>2(base10):11111111111111111111111111111101(base2)=-3(base10)
与左移相反,右移一位在原数字基础上除以2
64>>1//32
无符号右移
将a的二进制表示向右移b(<32)位,丢弃被移出的位,并使用0在左侧填充。
用法:a>>>b
在非负数来说,9>>>2和9>>2都是一样的结果
9(base10):00000000000000000000000000001001(base2)
--------------------------------
9>>>2(base10):00000000000000000000000000000010(base2)=2(base10)
而对于负数来说,结果就大有不同了,因为>>>不保留符号,当负数无符号右移时,会使用0填充
-9(base10):11111111111111111111111111110111(base2)
--------------------------------
-9>>>2(base10):00111111111111111111111111111101(base2)=1073741821(base10)
可以使用无符号右移来判断一个数的正负
functionisPos(n){ return(n===(n>>>0))?true:false; } isPos(-1);//false isPos(1);//true
虽然-1>>>0不会发生右移,但-1的二进制码已经变成了正数的二进制码,-1>>>0结果为4294967295
Javascript进制转换
toString
toString常用于将一个变量转为字符串,或是判断一个变量的类型,例如:
letarr=[]
Object.prototype.toString.call(arr)//[objectArray]
你应该没想过toString可以用于进制转换,请看下面例子:
(18).toString(2)//10010(base2)
(18).toString(8)//22(base8)
(18).toString(16)//12(base16)
参数规定表示数字的基数,是2~36之间的整数,若省略该参数,则使用基数10。该参数可以理解为转换后的进制表示。
parseInt
parseInt常用于数字取整,它同样可以传入参数用于进制转换,请看下面例子:
parseInt(10010,2)//18(base10)
parseInt(22,8)//18(base10)
parseInt(12,16)//18(base10)
第二个参数表示要解析的数字的基数,该值介于2~36之间。如果省略该参数或其值为0,则数字将以10为基础来解析。如果该参数小于2或者大于36,则parseInt将返回NaN。
记得有道面试题是这样的:
//问:返回的结果
[1,2,3].map(paseInt)
接下来,我们来一步一步的看下过程发生了什么?
parseInt(1,0)//基数为0时,以10为基数进行解析,结果为1
parseInt(2,1)//基数不符合2~36的范围,结果为NaN
parseInt(3,2)//这里以2为基数进行解析,但3很明显不是一个二进制表示,故结果为NaN//题目结果为
[1,NaN,NaN]
手动实现进制转换
虽然JavaScript为我们内置了进制转换的函数,但手动实现进制转换有利于我们理解过程,提高逻辑能力。对于初学者来说也是一个很不错的练习例子。以下只简单实现非负整数的转换。
十进制转二进制
基于“除二取余”思路实现
functiontoBinary(value){ if(isNaN(Number(value))){ throw`${value}isnotanumber` } letbits=[] while(value>=1){ bits.unshift(value%2) value=Math.floor(value/2) } returnbits.join('') }
使用
toBinary(36)//100100
toBinary(12)//1100
二进制转十进制
基于“取幂相加”思路实现
functiontoDecimal(value){ letbits=value.toString().split('') letres=0 while(bits.length){ letbit=bits.shift() if(bit==1){ //**为幂运算符,如:2**3为8 res+=2**bits.length } } returnres }
使用
toDecimal(10011)//19
toDecimal(11111)//33
写在最后
本文为大家介绍了进制和位运算的相关知识,旨在温故知新。我们只需要大概了解就好,因为在开发中真的用得少,至少我只用过~~来取整。而类似于~~这种取整操作还是尽量少用为好,对于其他开发者来说,可能会影响到代码可读性。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。