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

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

先来看十进制的表示。举个例子,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+an1×10n1++a1×10+a0
即十进制数字 x x x a n a n − 1 ⋯ a 1 a 0 a_na_{n-1}\cdots a_1a_0 anan1a1a0 的形式。

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

如果现在要把十进制转化成二进制,就是将上述式子右边的基数 ( 1 0 n , 1 0 n − 1 , ⋯   , 10 , 1 ) (10^n,10^{n-1},\cdots,10,1) (10n,10n1,,10,1) 换成 ( 2 n , 2 n − 1 , ⋯   , 2 , 1 ) (2^n,2^{n-1},\cdots,2,1) (2n,2n1,,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+bn1×2n1++b1×2+b0
于是十进制 x x x 表示成二进制的形式就是 b n b n − 1 ⋯ b 1 b 0 b_nb_{n-1}\cdots b_1b_0 bnbn1b1b0 了。

现在的关键是怎么求取系数呢?答案是取余。什么意思?举个例子,十进制数字 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)

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值