进制简介
进制也称为进位计数制,可以用有限的数字符号代表所有的数值。可使用的数字符号的数目称为基数或者底数,基数为n,即可称为n进位制,简称n进制。
对于任何一种进制---X进制,表示在每一位数上运算时,都逢X进一位。十进制逢十进一,十六进制逢十六进一,二进制逢二进一,以此类推,x进制就是逢x进一。
十进制(Decimal):平时我们最常用的是十进制,由0,1,2,3,4,5,6,7,8,9这10个阿拉伯数字组成。
二进制(Binary):在计算机中使用的是二进制,由0,1组成。
八进制(Octal):由于二进制的基数R比较小,书写和阅读不方便,所以在小型计算机中引入了八进制,由0,1,2,3,4,5,6,7组成,每个数码正好对应三位二进制。
十六进制(Hexadecimal):由于二进制在使用中位数太长,不容易记忆和书写,所以又提出了十六进制,由0-9加上字母A-F组成。
同一个数值可以用不同的进制表示,如66:
十进制:66
二进制:1000010
八进制:0102
十六进制:42
进制相关概念
数码:将数值中的每一位数字称为数码位数:数码在这个数值中的位置,从右向左开始递增。基数:每一位数码可以用多少数字来表示,例如:二进制中每一位的数码只能用0或1来表示,所以二进制的基数为2。基数其实就是所谓的进制,十进制基数为十,二进制基数为二。位权:处在某一位置上的数码所表示数值的大小,称为该位的位权。公式为:基数的位数次幂。
如:十进制的123:
- 123中的数字:1,2,3则称为数码。
- 123中3的位数为0,2的位数为1,1的位数为2,从右向左从0开始递增。
- 123是用十进制表示的,所以123的基数为10。
- 123中3它表示的位权为10^0=1,2的位权为10^1=10,1的位权为1*10^2=100。
进制转换
进行进制转换前,我们先了解一下各个进制间的关系:
| 十进制 | 二进制 | 八进制 | 十六进制 |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 |
| 2 | 10 | 2 | 2 |
| 3 | 11 | 3 | 3 |
| 4 | 100 | 4 | 4 |
| 5 | 101 | 5 | 5 |
| 6 | 110 | 6 | 6 |
| 7 | 111 | 7 | 7 |
| 8 | 1000 | 10 | 8 |
| 9 | 1001 | 11 | 9 |
| 10 | 1010 | 12 | A |
| 11 | 1011 | 13 | B |
| 12 | 1100 | 14 | C |
| 13 | 1101 | 15 | D |
| 14 | 1110 | 16 | E |
| 15 | 1111 | 17 | F |
| 16 | 10000 | 20 | 10 |
十进制转二进制
计算方式:使用除基取余法,也就是使用十进制的整数除以二进制的基数2,余数为权位上的数,得到的商继续除以2,直到商为0为止。读数时,从最后一位读起。
例如:
十进制数:67转二进制后,二进制为:1000011
计算过程如下:
| 第N次运算 | 运算 | 商 | 余数 |
|---|---|---|---|
| 第1次 | 67/2 | 33 | 1 |
| 第2次 | 33/2 | 16 | 1 |
| 第3次 | 16/2 | 8 | 0 |
| 第4次 | 8/2 | 4 | 0 |
| 第5次 | 4/2 | 2 | 0 |
| 第6次 | 2/2 | 1 | 0 |
| 第7次 | 1/2 | 0 | 1 |
计算完成后,从最后一位读起,结果为:1000011
以上是十进制整数部分转二进制的计算方式,我们再来看一下小数部分是如何转换的。
小数部分的计算方式:使用了乘基取整法,使用小数乘以二进制的基数2,整数部分为权位上的数,小数部分继续乘以2,知道小数部分为0为止。读数时,从第一位开始读起。
例如:
0.2转二进制后,二进制为:0.001100110011001100110011001100110011001100110011001101...
计算过程如下:
| 第N次运算 | 运算 | 积 | 整数部分 |
|---|---|---|---|
| 第1次 | 0.2*2 | 0.4 | 0 |
| 第2次 | 0.4*2 | 0.8 | 0 |
| 第3次 | 0.8*2 | 1.6 | 1 |
| 第4次 | 0.6*2 | 1.2 | 1 |
| 第5次 | 0.2*2 | 0.4 | 0 |
| 第6次 | 0.4*2 | 0.8 | 0 |
计算完成后,读数从第一位读起。可以看到在第5次计算的时候与第1次是一样的,形成了一个循环,所以0.2的二进制是一个无限循环的数值:0. 0011 0011 0011...。
二进制转十进制
计算方法:把二进制按权展开,相加既得十进制。
例如
十进制数:1000011转十进制后,十进制为:67
计算过程如下:
| 二进制: | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
|---|---|---|---|---|---|---|---|
| 位数 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
| 公式 | 1*2^6 | 0*2^5 | 0*2^4 | 0*2^3 | 0*2^2 | 1*2^1 | 1*2^0 |
| 结果 | 64 | 0 | 0 | 0 | 0 | 2 | 1 |
最后将结果相加:64 + 0 + 0 + 0 + 0 + 2 + 1 = 67
十六进制转二进制
计算方式:和十进制的计算方式一样,使用除基取余法,从最后一位读起。
例如:
67的十六进制为43,将43转为二进制为0100 0011
需要将十六进制拆分为以4个二进制为单位,也就是4,3。然后对4和3分别使用除基取余法,计算的结构如果不足4位,则在最左边补零。
4的计算过程如下:
| 第N次运算 | 运算 | 商 | 余数 |
|---|---|---|---|
| 第1次 | 4/2 | 2 | 0 |
| 第2次 | 2/2 | 1 | 0 |
| 第3次 | 1/2 | 0 | 1 |
计算完成,从最后一位读起,计算结果为:100,不足4位在最左边补零,最终结果为:0100。
3的计算过程如下:
| 第N次运算 | 运算 | 商 | 余数 |
|---|---|---|---|
| 第1次 | 3/2 | 1 | 1 |
| 第2次 | 1/2 | 0 | 1 |
计算完成,从最后一位读起,计算结果为:11,不足4位在最左边补零,最终结果为:0011。
然后将两次运算结果合并:01000011
二进制转十六进制
计算方式:将二进制从右向左以4位一组的形式按权展开,不足4位时在最左边补零,最后相加得到一位十六进制的数。
例如:
二进制为1000011转为十六进制为43
首先将二进制1000011从右向左以4位一组分开,不足4位补零,结果为:
01000011
0100计算过程如下:
| 二进制: | 0 | 1 | 0 | 0 |
|---|---|---|---|---|
| 位数 | 3 | 2 | 1 | 0 |
| 公式 | 0*2^3 | 1*2^2 | 0*2^1 | 0*2^0 |
| 结果 | 0 | 4 | 0 | 0 |
最后将结果相加:0 + 4 + 0 + 0 = 4,0100 = 4
0011计算过程如下:
| 二进制: | 0 | 0 | 1 | 1 |
|---|---|---|---|---|
| 位数 | 3 | 2 | 1 | 0 |
| 公式 | 0*2^3 | 0*2^2 | 1*2^1 | 1*2^0 |
| 结果 | 0 | 0 | 2 | 1 |
最后将结果相加:0 + 0 + 2 + 1 = 3,0011 = 3
最终结果为:43
十六进制转十进制
计算方式:将十六进制按权展开,相加既得十进制数。
例如:
十六进制43转十进制,十进制数为:67
计算过程如下:
| 十六进制: | 4 | 3 |
|---|---|---|
| 位数 | 3 | 2 |
| 公式 | 4*16^1 | 3*16^0 |
| 结果 | 64 | 3 |
计算完成,将结果相加:64 + 3 = 67
十进制转十六进制
计算方式:使用除基取余法,十进制数除以十六进制的基数16,余数为权位上的树,使用商继续除以16,直到商为0为止,读树时从最后一位起读。
例如:
十进制67转十六进制,十六进制为43
计算过程如下:
| 第N次运算 | 运算 | 商 | 余数 |
|---|---|---|---|
| 第1次 | 67/16 | 4 | 3 |
| 第2次 | 4/16 | 0 | 4 |
计算完成,读数从最后一位读起,结果为:43
javascript中的进制转换
toString
平常使用toString方法,一般是将非字符串类型转换为字符串类型,但是它还有一个功能则是用于将number类型的数值进行进制转换。
语法:
numObj.toString([radix])
(67).toString(2) // '1000010'
(67).toString(8) // '103'
(67).toString(16) // '43'
(67).toString(1) // RangeError: toString() radix argument must be between 2 and 36
radix参数指定数字到字符串的转换的基数,基数需要大于等2,小于等于36。如果未指定radix参数,则默认基数为10。
parseInt
parseInt的作用是解析一个字符串并返回指定基数的十进制整数。
语法:
parseInt(string, radix);
radix参数指定数字到字符串的转换的基数,基数需要大于等2,小于等于36。注意:如果未指定radix参数,10不是默认值。ECMAScript 5 规范不再允许parseInt函数的实现环境把以0字符开始的字符串作为八进制数值,也就是说现在只有两种情况:如果radix是undefined、0或未指定的,参数会被假定以10为基数来解析,如果数值以字符对0x或0X开头,会假定以16为基数来解析。
parseInt('1000011', undefined) // 1000011 按十进制解析
parseInt('1000011', 2) // 67 按二进制解析
parseInt('08') // 8 按十进制解析
parseInt('0x43') // 67 按十六进制解析
实战题
['1', '2', '3'].map(parseInt)
有些同学看到这题,脑子里一下就有了答案:[1, 2, 3];
恭喜你,回答错误。
首先我们先来分析一下代码:
- 有一个元素为
string的Array - 使用了
map方法 - 在
map方法中传入的回调函数是parseInt方法
我们先搞清楚map方法,它需要传入一个回调函数,这个函数中有三个参数:
currentValue:数组中正在处理的当前元素。index:数组中正在处理的当前元素的索引。array:map方法调用的数组,也就是['1', '2', '3']
然后是parseInt方法,通过上面我们知道parseInt需要传两个参数:
-
string:需要被转为number类型的字符串
-
radix:基数,范围在2-36之间(包括2和36),为0,undefined或不传则默认为10,超出该范围,
parseInt无法解析则返回NaN
回过头再来看代码:
['1', '2', '3'].map(parseInt)
转为
['1', '2', '3'].map((currentValue, index, array) => {
// 第一次循环:parseInt('1', 0);
// 第二次循环:parseInt('2', 1);
// 第二次循环:parseInt('3', 2);
return parseInt(currentValue, index);
});
- 第一次循环中调用
parseInt,值传入的'1',radix传入的0,parseInt的基数则默认使用10(十进制)来解析,结果为1 - 第二次循环中调用
parseInt,值传入的'2',radix传入的1,上面我们说过,radix的值需要大于等于2,小于等于36,超出则无法解析,所以记过为:NaN - 第三次循环中调用
parseInt,值传入的'3',radix传入的2,radix也是正确的,但是二进制中是由0和1组成的,3不是一个正确的二进制,解析会出错,所以结果为:NaN
最终结果为:[1, NaN, NaN]
['1.1', '2', '0.3'].map(parseInt)
这道题的结果会是多少呢?
公布答案:[1, NaN, 0]
我们来看下代码分析:
['1.1', '2', '0.3'].map(parseInt)
转为
['1.1', '2', '0.3'].map((currentValue, index, array) => {
// 第一次循环:parseInt('1.1', 0);
// 第二次循环:parseInt('2', 1);
// 第二次循环:parseInt('0.3', 2);
return parseInt(currentValue, index);
});
注意:这道题比上面那道题多考一个知识点:parseInt只会解析数值,遇到非数值类型则会停止,并返回之前解析的数值。
- 第一次循环中调用
parseInt,值传入的'1.1',radix传入的0,parseInt的基数则默认使用10(十进制)来解析,解析完1后,继续向下解析遇到小数点符号,遇到非数值类型停止解析,返回之前解析的数值,结果为1 - 第二次循环中调用
parseInt,值传入的'2',radix传入的1,radix的值需要大于等于2,小于等于36,超出则无法解析,所以记过为:NaN - 第三次循环中调用
parseInt,值传入的'0.3',radix传入的2,以二进制来解析,遇到0,解析成功,继续向下解析遇到小数点符号,遇到非数值类型停止解析,返回之前解析的数值,结果为0
最终结果为:[1, NaN, 0]
总结
除基取余法:进制数x转n进制,使用x除以n进制的基数n,余数为权位上的数值,将商继续除以n,直到商为0为止。读数时,从最后一位读起(倒序)。乘积取整法:进制数x转n进制,使用x乘以n进制的基数n,获得的积的整数部分为权位上的数值,将小数部分继续乘以n,直到小数部分为0为止。读数时,从第一个读起(正序)。十进制的数转任何进制数,整数部分都是使用除基取余法,小数部分使用乘积取整法。任何进制数转十进制,都使用按权展开相加- 二进制转为其它进制(不包括十进制),需要先根据进制从右向左进行分组,不足时补零,如:转4进制,需要以2位二进制为一组,转8进制需要以3位二进制为一组,转16进制需要以4位二进制为一组。然后按权展开相加。
- 在javascript中也有内置的进制转换方法:
number.toString(radix):将number类型转换为其它进制数(字符串类型),radix不传,为0或为undeined时,默认为10(十进制),范围在2-36之间(包括2和36),超出则会报错(RangeError)。parseInt(string, radix):根据基数来解析字符串,并返回一个十进制的整数。radix不传,为0或为undeined时,默认为10(十进制),范围在2-36之间(包括2和36),当字符串以0X或者0x开头则默认使用16(十六进制)来解析。