将十进制转换成其它进制,是怎么进行的呢?下面来详细叙述一下:
先来看十进制的表示。举个例子,666 这个数字,我们的读法是 “6百6十6”,意味着它是由各个位数(百位、十位、个位)上的数字累加成的,写成式子,表示如下:
666
=
6
×
1
0
2
+
6
×
10
+
6
666 = 6\times10^2+6\times10+6
666=6×102+6×10+6
可以看出组成十进制数的各个数字恰好是右边式子(多项式)的系数。对于一般情况,给定任何一个十进制数
x
x
x,它可以写成如下公式:
x
=
a
n
×
1
0
n
+
a
n
−
1
×
1
0
n
−
1
+
⋯
+
a
1
×
10
+
a
0
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
即十进制数字
x
x
x 为
a
n
a
n
−
1
⋯
a
1
a
0
a_na_{n-1}\cdots a_1a_0
anan−1⋯a1a0 的形式。
有了这个式子,那么我们转化成其它进制就好办了。
如果现在要把十进制转化成二进制,就是将上述式子右边的基数
(
1
0
n
,
1
0
n
−
1
,
⋯
 
,
10
,
1
)
(10^n,10^{n-1},\cdots,10,1)
(10n,10n−1,⋯,10,1) 换成
(
2
n
,
2
n
−
1
,
⋯
 
,
2
,
1
)
(2^n,2^{n-1},\cdots,2,1)
(2n,2n−1,⋯,2,1) 的基数,那么就有公式:
x
=
b
n
×
2
n
+
b
n
−
1
×
2
n
−
1
+
⋯
+
b
1
×
2
+
b
0
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
于是十进制
x
x
x 表示成二进制的形式就是
b
n
b
n
−
1
⋯
b
1
b
0
b_nb_{n-1}\cdots b_1b_0
bnbn−1⋯b1b0 了。
现在的关键是怎么求取系数呢?答案是取余。什么意思?举个例子,十进制数字 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) # 将列表形式转化成字符串形式输出
相应地,转换成八进制,就只需要将上述的 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) # 将列表形式转化成字符串形式输出
但是转化成十六进制呢?那就不单单用上面的思路了!(还需要对余数进行处理!)
上面这句话什么意思呢?那我们要看十六进制的表示形式了。因为十六进制中有字符 ‘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)
那么如果转化成更高的进制呢?比如说 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)
第二个思路是将 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)
有了上面这些不同进制的介绍,这样我们关于将十进制转化成任何进制都会觉得很容易了。如果需要将十进制转化成 K进制,此时的 K 若小于10,那么直接按照上面转二进制的方法就可以了(把代码中的 2 换作 K 即可);若 K 大于 10,则需要先建立映射表,当余数从 0 开始到 K-1 都有映射时(比如上面介绍的 16 进制),代码跟转二进制一样(只是多了个建立映射的步骤),当映射从 1开始到 K时,这种情况需要将它进行平移,或者对满进制做一个判断处理(比如上面介绍的 26 进制),其余就跟转二进制一样了。
======================================================
作者:哈哈村长
(转载请注明出处:https://blog.csdn.net/Deeven123/article/details/82942078)