在上一章我们讲了python的二进制和十进制互相转换,因为内容太长,剩下的部分我们放到这一章来讲,如果没有看过上一章,我把链接贴到这里:https://blog.csdn.net/ttug22/article/details/145637727?spm=1001.2014.3001.5501http://pyhon-整数以及内存表示方式 因为我们已经明白了二进制和十进制相互转换的方法,所以理论上八进制和十进制的相互转换以及十六进制的相互转换是很相似的。
但是我们一开始不谈八进制,十六进制到十进制的相互转换,因为我觉得首先搞清楚二进制,八进制,十六进制的相互转换,问题就会变得容易。因为八进制和十六进制都可以转换二进制,二进制和十进制的相互转换,我们已经知道了,当然这种方法对于某些人对数字敏感的人来讲,可能觉得过于啰嗦,但是对于一看到数字就头疼的人来讲,也不失是一种好的办法。
二进制和八进制的相互转换:
无论是八进制还是二进制,在计算机内部的表示都是一样的,也就是计算机对于八进制来讲,也是二进制来存储的,我们谈八进制和二进制的相互换转,只是书写形式的转换。对于八进制来讲,就是三个比特(bit)代表一个八进制数字,也就是三个二进制位表示一个八进制数字。 不考虑符号,三个二进制能代表的最大值是111,也就是1*2**2+1*2**1+1*2**0 = 4+2+1=7,二最小值是000,也就是0。这也就是为八进制最大的数字是7的原因。以16位的长度来说明,看一下下面这张图,这个我们上一章讲到过:
我们都知道这个值是-1,二进制就是0b1111111111,对于八进制如何表示呢?刚才我们讲了三个二进制表示一个八进制,我们从低位开始,每三位转换成一个八进制:有16位,所以我们有5个三位,还有最后一个位,我们可以把最后剩下的一位扩展成001。因为全是一,所以转化成8进制之后位0o177777。那反过来,将八进制的一位转换位三位,就变成了二进制。这里面特别注意一下最后一位,如果我们转换位二进值的时候得到是001,因为只有16位,所以最后一个值我们只取1。我们始终要有这样的认知,八进制和二进制虽然书写形式不同,但是内存中存储的值是一样的,都是二进制。因为python都是有符号数,对于内存中的最高位,如果是1则代表负数,为0则代表正数。
再说明一下,如果计算机用16位表示整数,假如有一个数是5,我们写二进制的时候,一般写成0b101,而不会写成0b0000000000000101,同样八进制也一样,写成0o5,计算机会将高位补0。对于同一个书写表示,计算机用16存储整数和计算机用32位存储整数可能得到不同的值。还是拿0b1111111111111111来说,在16位表示的情况下,最高位是1,所以肯定是负数,我们前面说过了,值是-1。对于32位的机器,内存中是00000000000000001111111111111111,因为剩下的16位都是0,所以这表示是一个正数,是2**16-1。
书写形式和内存表示的差别:
在之前的描述中,为了表明书写形式和计算机内存的关系,我们规定了计算机内部存储的位数,实际上因为python可以表示无穷大,只要内存够用。所以在python的世界中0b1111111111111111,永远都只是一个正数。对于C来讲,如果是short类型,那么这个值就是-1。那python中一个二进制如何表示的-1呢,答案是-0b1,注意前面加了一个符号-。所以在python中,如果你想表示一个负数,必须加在前面加负号,对于-0b1111111111111111,它的值是-2**16+1,如下代码所示:
print(-0b1111111111111111)#输出为-65535
print(-0b1)#输出为-1
如果你一开始读我的文章,跟着我的思路走,走到这里你可能会觉得有点惊讶。将负数十进制转化为二进制的时候,我们是先用绝对值转化为二进制,然后按位取反加一得到负数的二进制,这时候得到的二进制的书写形式,和计算机内存的真实表示是一样的,前提是我们规定了这个数表示的位数。
但是我们需要有一个清醒的认识,我们书写的二进制和计算机内存真实存储的形式不是必然一一对应的。还是拿16位的长度来讲,0b1111111111111111和-0b1在计算机内存中都是1111111111111111,但是如果不是16位,那么这两个的值完全不一样。
二进制和十六进制的相互转换:
上面讲了二进制和八进制的相互转换,对于16进制来讲,就很简单了。十六进制和八进制不一样的地方是16进制需要用4个比特表示位,所以十六进制能表示的最大值位1111,也就是15,最小值为0000,也就是0。因为10以上的数字,我们书写的时候肯定是两位,这样对于15,究竟是表示15一个位,还是1和5两个位呢,这就没法区分,所以对于大于等于10的数字,我们用字母A-F(a-f),大小写都可以。所以10->A,11->B,12->C,13->D,14->E,15->F,我们还是拿0b1111111111111111来说,因为四位表示一位,所以可以用4个16进制表示,结果为0xFFFF。反过来,要将十六进制表示为二进制,只需要将每一位的值转化为4位二进制即可,这点在二进制转八进制已经说的很明白,不再赘述。
八进制和十六进制的相互转换:
目前来看,没有直接转换的公式或者方法。一般的做法是将八进制或者十六进制转化为二进制,然后再做转换。
八进制,十六进制和十进制的相互转换:
一般有两种方式,一种就是直接转换,另一种就间接转换,将八进制或者十进制都转成二进制,然后根据需要转换成八进制或者十进制。
间接转换,我相信通过前面以及上一章的学习,大家都会学会了如何转换。如果真的是没学会,那你可以私信我。
对于直接转换接,上一章我们学习和二进制和十进制的相互转换,八进制,十六进制和二进制很相似,只是二进制的权是2,八进制是8,十六进制是16。
在这里就不再详细记述是如何转换的,但是有一些点需要提醒一下。
1,如果是python,将八进制或者十六进制转化为十进制的时候,直接利用等比数列加法就行,然后如果前面负号,转换的十进制加上负号即可。
例如:-0xFFFF 转化为十进制 (16**0)*15+(16**1)*15+(16**2)*15+(16**3)*15=65535,因为前面有负号,所以为-65535
同样,八进制-0o177777,转化为十进制(8**0)*7+(8**1)*7+(8**2)*7+(8**3)*7+(8**4)*7+(8**5)*1=65535,因为前面有负号,所以为-65535
2,如果不是python,那么就得观察这个类型的数据长度,看看最高位表示是不是1,如果是1,那就转化为二进制,然后再做十进制转换。
还是假设正数的长度为16,-0o177777,你就不能按照上面的算法算了,可以将-0o177777转化为二进制,也就是-0b1111111111111111,然后按照最高位参与运算的方式(二进制转十进制请参照上一章),我们得出-1,因为前面还有个负号,负负为正,所以这个值就是1
3,十进制转化为八进制或者十六进制,先用绝对值转化为八进制或者16进制,然后在前面加负号即可。
在上一章的十进制转二进制算法中,我们规定了内存中数据的长度,我们转化出的二进制的书写形式和内存上的表示形式是一致的,代码如下:
def get_place(a,bits):
#是否复数的标志
minus = False
#对参数取绝对值
if a < 0:
a = abs(a)
minus = True
#定义一个列表用来存放每一位
res = []
#如果a大于0,循环继续,如果a小于等于0,跳出循环
#实际上,a不会小于0,最后只能为0
while a > 0:
#先进行模除,得到最低位
tmp = a % 2
#去掉最低位
a = int(a /2)
#得到的最近位插入列表第一位,因为我们最先或许低位的值
#所以最后得到的是最高位,需要放在最前面
res.insert(0,tmp)
#如果没有bits位,则高位补0
while len(res) <bits:
res.insert(0, 0)
#如果是复数
if minus:
i = len(res)-1
#按位取反
while i >= 0:
if res[i] == 0:
res[i] = 1
else:
res[i] = 0
i = i - 1
i = len(res)-1
#将取反的结果加一,因为是列表,我们们从列表的最后一位加1
#如果该列表元素加一之后不等2,就结束循环,如果等于2,将该位置0
#继续对数组的上一位加1
while i >= 0:
tep = res[i] + 1
if tep == 2:
res[i] = 0
else:
res[i] = res[i] + 1
break
i = i - 1
#打印这个列表
print(res)
get_place(26,16)
get_place(-26,16)
但是如果对于python的话,那就不适用了,我们修改代码,重新实现十进制到二进制的转换,同时输出以字符串的形式,因为这样子更像是书写形式,而不是内存表示形式。
def get_b(a):
#是否复数的标志
minus = False
#对参数取绝对值
if a < 0:
a = abs(a)
minus = True
#定义一个列表用来存放每一位
res = []
#如果a大于0,循环继续,如果a小于等于0,跳出循环
#实际上,a不会小于0,最后只能为0
while a > 0:
#先进行模除,得到最低位
tmp = a % 2
#去掉最低位
a = int(a /2)
#得到的最近位插入列表第一位,因为我们最先或许低位的值
#所以最后得到的是最高位,需要放在最前面
res.insert(0,str(tmp))
res = '0b'+"".join(res)
if minus:
res = '-'+res
print(res)
get_b(26)
get_b(-26)
上面的代码删掉了负数情况下根据原码取得补码的过程,并且将列表中存储类型有正数改为字符串。如果是负数,则直接在前面加上负号即可。这段代码的输出是:
0b11010
-0b11010
同样,对于八进制,我们将权修改成8即可,代码如下:
def get_o(a):
#是否复数的标志
minus = False
#对参数取绝对值
if a < 0:
a = abs(a)
minus = True
#定义一个列表用来存放每一位
res = []
#如果a大于0,循环继续,如果a小于等于0,跳出循环
#实际上,a不会小于0,最后只能为0
while a > 0:
#先进行模除,得到最低位
tmp = a % 8
#去掉最低位
a = int(a /8)
#得到的最近位插入列表第一位,因为我们最先或许低位的值
#所以最后得到的是最高位,需要放在最前面
res.insert(0,str(tmp))
res = '0o'+"".join(res)
if minus:
res = '-'+res
print(res)
get_o(26)
get_o(-26)
这个没什么可说的,结果如下:
0o32
-0o32
对于十六进制,我们除了将权值修改,还要将大于等于10的值转化为对应的字母,这里我们做了一个字典,数字直接对应字母,代码如下:
hex_dict={
0:"0",1:"1",2:"2",3:"3",4:"4",5:"5",
6:"6",7:"7",8:"8",9:"9",10:"A",11:"B",
12:"C",13:"D",14:"E",15:"F"
}
def get_h(a,bits):
#是否复数的标志
minus = False
#对参数取绝对值
if a < 0:
a = abs(a)
minus = True
#定义一个列表用来存放每一位
res = []
#如果a大于0,循环继续,如果a小于等于0,跳出循环
#实际上,a不会小于0,最后只能为0
while a > 0:
#先进行模除,得到最低位
tmp = a % 16
#去掉最低位
a = int(a /16)
#得到的最近位插入列表第一位,因为我们最先或许低位的值
#所以最后得到的是最高位,需要放在最前面
res.insert(0,hex_dict[tmp])
res = '0x'+"".join(res)
if minus:
res = '-'+res
print(res)
get_h(26,16)
get_h(-26,16)
输出的结果为:
0x1A
-0x1A
到此为止,我们已经讲完的整数的内存表示以及二进制,八进制,十进制,十六进制之间的相互转换。如果有任何疑问,欢迎提问。