您的位置:首页 > 编程语言 > Python开发

从十进制到二进制、八进制、十六进制,延伸到 K 进制 ( Python 编程)

2018-10-05 10:54 288 查看

将十进制转换成其它进制,是怎么进行的呢?下面来详细叙述一下:

先来看十进制的表示。举个例子,666 这个数字,我们的读法是 “6百6十6”,意味着它是由各个位数(百位、十位、个位)上的数字累加成的,写成式子,表示如下:
666=6×102+6×10+6 666 = 6\times10^2+6\times10+6 666=6×102+6×10+6
可以看出组成十进制数的各个数字恰好是右边式子(多项式)的系数。对于一般情况,给定任何一个十进制数 xxx,它可以写成如下公式:
x=an×10n+an−1×10n−1+⋯+a1×10+a0 x = a_n\times10^n+a_{n-1}\times10^{n-1}+\cdots+a_1\times10+a_0 x=an​×10n+an−1​×10n−1+⋯+a1​×10+a0​
即十进制数字 xxx 为 anan−1⋯a1a0a_na_{n-1}\cdots a_1a_0an​an−1​⋯a1​a0​ 的形式。

有了这个式子,那么我们转化成其它进制就好办了。

如果现在要把十进制转化成二进制,就是将上述式子右边的基数 (10n,10n−1,⋯ ,10,1)(10^n,10^{n-1},\cdots,10,1)(10n,10n−1,⋯,10,1) 换成 (2n,2n−1,⋯ ,2,1)(2^n,2^{n-1},\cdots,2,1)(2n,2n−1,⋯,2,1) 的基数,那么就有公式:
x=bn×2n+bn−1×2n−1+⋯+b1×2+b0 x = b_n\times2^n+b_{n-1}\times2^{n-1}+\cdots+b_1\times2+b_0 x=bn​×2n+bn−1​×2n−1+⋯+b1​×2+b0​
于是十进制 xxx 表示成二进制的形式就是 bnbn−1⋯b1b0b_nb_{n-1}\cdots b_1b_0bn​bn−1​⋯b1​b0​ 了。

现在的关键是怎么求取系数呢?答案是取余。什么意思?举个例子,十进制数字 456 要得到各个位数的系数怎么办?过程如下:
用 456 对 10 取余得到一个个位上的 6 (商为 45),
再用 45 对 10 取余得到一个十位上的 5(商为 4),
再用 4 对 10 取余得到一个百位上的 4(商为0)。
是不是很简单?

相似地,那么这个十进制数字 456 转换成二进制,就只需将对 10 取余换成对 2 取余就行了。过程如下:
先用数字 456 对 2 取余得到一个余数 0 (商为 228),
再用 228 对 2 取余得到一个余数 0(商为 114),
再用 114 对 2 取余得到一个余数 0(商为 57),
再用 57 对 2取余得到一个余数 1(商为28),
再用 28 对 2 取余得到一个余数 0(商为14),
再用 14 对 2 取余得到一个余数 0(商为 7),
再用 7 对 2 取余得到一个余数 1(商为 3),
再用 3 对 2 取余得到一个余数 1(商为1),
再用 1 对 2 取余得到一个余数 1(商为0)。
上述的所有余数就是二进制的各个位数上的系数,从后往前排列,得到 111001000,这个二进制数就是十进制数字 456 的二进制表示。

Python 代码如下:

def dec2bin(n):  # 注:输入的十进制 n>=0且为整数
rest = []
if n==0:
return 0
while(n>0):
rest.append(str(n%2))  # 得到各个位数上的余数
n = int(n/2)
rest.reverse()  # 将余数从后往前排列
return ''.join(rest) # 将列表形式转化成字符串形式输出
[/code]

相应地,转换成八进制,就只需要将上述的 2 换成 8 就可以了。

Python 代码如下:

def dec2oct(n):  # 注:输入的十进制 n>=0且为整数
rest = []
if n==0:
return 0
while(n>0):
rest.append(str(n%8))  # 得到各个位数上的余数
n = int(n/8)
rest.reverse()  # 将余数从后往前排列
return ''.join(rest) # 将列表形式转化成字符串形式输出
[/code]

但是转化成十六进制呢?那就不单单用上面的思路了!(还需要对余数进行处理!)

上面这句话什么意思呢?那我们要看十六进制的表示形式了。因为十六进制中有字符 ‘A’、‘B’、‘C’、‘D’、‘E’、‘F’,它们分别对应十进制中的 10、11、12、13、14、15。所以需要将这些字符与对应整数做一个映射才行,即先构建一个如下的映射:
1 —> 1, 2 —> 2, 3 —> 3, 4 —> 4, 5 —> 5,6 —> 6,⋯\cdots⋯
10 —> ‘A’, 11 —> ‘B’, 12 —> ‘C’, 13 —> ‘D’, 14 —> ‘E’, 15 —> ‘F’,
剩下的就跟之前一样了。

Python 代码如下:

def dec2hex(n):  # 注:输入的十进制 n>=0且为整数
rest = []
lists = list(map(chr, range(65,71)))  # 字符'A'、'B'、'C'、'D'、'E'、'F'
lists = list(range(10))+lists
nums = list(range(16))
dicts = dict(zip(nums, lists))   #  构建映射
if n==0:
return dicts[n]
while(n>0):
rest.append(str(dicts[n%16]))
n = int(n/16)
rest.reverse()
return ''.join(rest)
[/code]

那么如果转化成更高的进制呢?比如说 26 进制?下面先来看个 Leetcode 上的一个关于将十进制转换成 26 进制的题目吧(Leetcode 168. Excel Sheet Column Title)。描述如下:

Given a positive integer, return its corresponding column title as appear in an Excel sheet.
For example:
1 -> A
2 -> B
3 -> C

26 -> Z
27 -> AA
28 -> AB

Example 1:
Input: 1
Output: “A”
Example 2:
Input: 28
Output: “AB”
Example 3:
Input: 701
Output: “ZY”

对于这个题目,跟之前做 “十进制转 16 进制” 的思路是一样的,唯一的不同是,余数为 0 的表示有点不一样。详细解释一下:
在十六进制中:
(0)10(0)_{10}(0)10​—> (0)16(0)_{16}(0)16​,(1)10(1)_{10}(1)10​ —> (1)16(1)_{16}(1)16​,(2)10(2)_{10}(2)10​ —> (2)16(2)_{16}(2)16​,⋯\cdots⋯,(15)10(15)_{10}(15)10​ —> (F)16(\text{F})_{16}(F)16​,(16)10(16)_{10}(16)10​ —> (11)16(11)_{16}(11)16​

可以看到,将十进制转换成十六进制时,当十六进制满十六才进了一位。十进制中是 “满十进一”,十六进制中是 “满十六进一”,那么自然而然就想到 26 进制中是 “满二十六进一”。但是,题目给出的条件是 (26)10(26)_{10}(26)10​ —> (Z)26(\text{Z})_{26}(Z)26​,即 “满二十六并没有进一”。

有人会想,这会不会是 27 进制?答案肯定不会是,这明显是 26 进制(因为英文中只有 26 个字母啊)。那么,为什么 “满二十六并没有进一”?我们仔细来看一下,发现它并没有整数 0 对应的一项。上面是从整数 1 开始映射的,这就导致 26 也没有进位。

怎么解决上面的问题呢?有两种思路。

第一个是将映射区间向左平移一个单位,即用 0 来映射 ‘A’,那么,25 就会映射到 ‘Z’,26 就会映射到 ‘AA’(即此时有了 “满二十六进一”),剩下的就跟之前的 “十进制转十六进制” 一模一样了。在构造映射时,用 ‘0’ 映射到 ‘A’,用 ‘1’ 映射到 ‘B’,⋯\cdots⋯,用 ‘25’ 映射到 ‘Z’。为了满足题目要求,需要将输入的十进制整数 “减去1” 再进行映射。

Python 代码如下:

def dec2Title(n):  # 注:输入的十进制数 n为正整数
m = n-1 # 先把数字向左平移一个单位
rest = []
letters = list(map(chr, range(65,91)))
nums = list(range(26))
dicts = dict(zip(nums, letters))       # 构建映射
if m==0:
return dicts[m]
while(m>=0):  # 由于下面的商左移了,此处条件需要包含 “=” 情况
rest.append(str(dicts[m%26]))
m = int(m/26)-1  # 左移一个单位
rest.reverse()
return ''.join(rest)
[/code]

第二个思路是将 26 —> ‘Z’ 换成 ‘0’ —> ‘Z’(相当于 “满二十六归零”),这样就有了余数为 0 的情况了。但是只做这个转换还不够,比如说,十进制数 26 转化后的正确形式应该是 ‘Z’,但是由于将 ‘Z’ 当作进位制了(即 “满二十六归零”),按照上面的改动会得到 ‘AZ’ 的结果,即向前进位了个 ‘A’。现在需要处理的是:不要它在 ‘Z’ 时进位。处理方法是:每当被整除时,将商减去 1 就可以了,如果没有被整除,那么商的计算公式不变。

Python 代码如下:

def dec2Title(n):  # 注:输入的十进制 n为正整数
rest = []
letters = [chr(90)]+list(map(chr, range(65,90)))
nums = list(range(26))
dicts = dict(zip(nums, letters))      # 构建映射
while(n>0):
rest.append(str(dicts[n%26]))
n = int(n/26) if n%26!=0 else int(n/26)-1
rest.reverse()
return ''.join(rest)
[/code]

有了上面这些不同进制的介绍,这样我们关于将十进制转化成任何进制都会觉得很容易了。如果需要将十进制转化成 K进制,此时的 K 若小于10,那么直接按照上面转二进制的方法就可以了(把代码中的 2 换作 K 即可);若 K 大于 10,则需要先建立映射表,当余数从 0 开始到 K-1 都有映射时(比如上面介绍的 16 进制),代码跟转二进制一样(只是多了个建立映射的步骤),当映射从 1开始到 K时,这种情况需要将它进行平移,或者对满进制做一个判断处理(比如上面介绍的 26 进制),其余就跟转二进制一样了。

======================================================

作者:哈哈村长
(转载请注明出处:https://blog.csdn.net/Deeven123/article/details/82942078)

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐