之前已经详细的讨论了十进制整数以及小数和二进制之间的互转,详细的可以参考 理解进制转换的原理。
前段时间在 知乎 看到了这样的一个问题。
你品,你细品,如果让你把 7
进制数转成 8
进制数,是不是你会先把 7
进制数转成 10
进制数,然后再转成 8
进制数。下边就讨论一下这个问题,前提是你已经对二进制和十进制之间的互转已经很清楚了。不然的话,建议先看一下 理解进制转换的原理。
我们再重新思考一下进制,所谓进制无非是每一位有了不同的权重。
对于二进制权重依次是 $$…2^32^22^12^0$$
也就是 ... 8 4 2 1
所以对于二进制 1100
,转为十进制就是二进制的每一位乘以它的权重,即
1 × 8 + 1 × 4 + 0 × 2 + 0 × 1 = 12
。
那么问题来了,为什么是转成了十进制?
这里是关键了,因为我们说权重的时候,习惯性就用 10 进制去计算了权重。
那么这里换下思路,我们不用十进制去表示权重,而是用七进制去表示权重。
让我们熟悉一下七进制。
首先七进制用 7 个符号表示,即 0, 1, 2, 3, 4, 5, 6
再熟悉一下七进制的运算,满 7 进 1
2 + 6 = 11
3 + 4 = 10
2 * 2 = 4
$2^3=11$
好的,看起来有些别扭,但事实如此,哈哈。
让我们回到二进制的权重问题,看一下七进制下的权重。
对于二进制权重依次是 $$…2^32^22^12^0$$
也就是,... 11 4 2 1
所以对于二进制 1100
,转为七进制就是二进制的每一位乘以它的权重,即
1 × 11 + 1 × 4 + 0 × 2 + 0 × 1 = 11 + 4 = 15
所以二进制的 1100
在七进制中就是 15
。
我们直接将二进制转为了七进制!
所以,我们之所以要将其他进制先转换为十进制,就是因为进制的权重我们默认下都是在十进制下进行的。如果在程序中,我们算某个权重,比如 $2^3$,结果一定是 8
,这也决定了,我们只能将其它进制先转为十进制。
1 | public int twoToTen(String two) { |
输入二进制 1100
,就会输出十进制的 12
了。
为什么是 10
进制的呢,因为上边我们累加以及算权重的时候,调用的加法、乘法、幂次,都是基于 10
进制的。
那么我们能否修改函数,直接把二进制转为七进制呢?
我们只需要重新定义加法、乘法、以及幂次,让运算都是基于七进制的即可。这样算出的权重就是基于七进制的,加法、乘法也就会是基于七进制的,最终的结果当然是一个七进制的数字了。
首先我们定义一个 Seven
类,进行七进制的加法以及乘法、幂次。
思想的话,参考 Leetcode
的第二题 大数相加 。
这里的乘法以及幂次,直接递归的进行了,没有进行任何优化,只用于演示,具体优化方法参考可以参考 LeetCode
的 29 题 以及 50 题。
此外,这里的加法只考虑了两个正数相加,减法也只考虑了减 1
。
1 | public final class Seven { |
有了七进制运算的类,我们就可以直接把二进制直接转换为七进制了。
1 | public int twoToSeven(String two) { |
上边如果输入 1100
,就会输出七进制的 15
了。
甚至,我们可以在函数增加一个参数,就可以将任意进制转为七进制了。
1 | public int anyToSeven(String two, int radix) { |
上边如果输入 1200 3
,也就是三进制的 1200
,就会输出七进制的 63
了。
当然上边的 any
只能是小于七进制的,因为我们里边的运算都是基于 7
进制的,允许的符号是 0 - 6
,如果大于七进制上边就会乱套了。
至于大于七进制的转为七进制,方法的话就类似于上边介绍的十进制转为二进制,此时权重是固定的,然后利用除法求出每一位的值。
因此我们至少还需要实现七进制的除法,然后利用十进制转为二进制的思想即可。这里就不写了,就交给大家了,哈哈。
ps: 上边的代码,没有做严格的测试,思想应该是对的,哈哈,发现问题可以和我交流。
总结一下
进制转换分为两大类。
低进制转到高进制,也就是我们上边详细讨论的。我们只需要把权重用高进制的数去表示,然后在某个进制下进行相乘相加即可。
高进制转到低进制,类比于我们熟悉的十进制转二进制,同样用高进制的数表示权重,此时我们在某个进制下通过除法来求出各个位即可。
其实不管高进制到低进制,还是低进制到高进制,都是基于下边的等式。
以十进制和二进制的转换为例。
$$…a\times2^4+b\times2^3+c\times2^2+d\times2^1+e\times2^0=2020$$
已知左边,就是低进制到高进制。已知右边,就是高进制到低进制。
左边权重的幂次的底决定了低进制是多少。
相乘相加在多少进制下进行,决定了最终转为了多少进制。
因此需要十进制中转根本原因就是我们手里的计算器,计算机,或者你自己的口算,所有的计算我们都默认在十进制下进行,数量这个概念我们也是用十进制表示的。
因此不管其他进制转十进制,还是十进制转其他进制都会很方便。
再补一句,如果自己去实现七进制下的加减乘除。为了减少我们的工作量,因为我们的计算机已经实现了十进制的加减乘除,所以我们可以将七进制转为十进制,然后进行相应的计算,最后再将结果转回七进制即可。而我之前实现的七进制类,相当于在十进制的基础上模拟了七进制的进位借位,所以更麻烦些。