进位计数法和不同进制数相互转换

进位计数法和不同进制数相互转换

进位计数制

一般我们常用的计数进位制有

  • 十进制:172
  • 二进制:10101100
  • 八进制:254
  • 十六进制:AC

例如:
69 = 6 ∗ 10 + 9 ∗ 1 = 6 ∗ 1 0 1 + 9 ∗ 1 0 0 69=6*10+9*1=6*10^1+9*10^0 69=610+91=6101+9100
这里的 10 10 10就是基(base),那么我们可以做一步抽象得到:
设 b a s e 为 k x = a n ∗ k n + ⋯ + a 1 ∗ k 1 + a 0 ∗ k 0 = ∑ i = 0 n a i ∗ k i 设base为k\\ x = a_n*k^n+\cdots+a_1*k^1+a_0*k^0=\textcolor{blue}{\sum_{i=0}^na_i*k^i} basekx=ankn++a1k1+a0k0=i=0naiki
当且讨论都是在整数范围,如果我们要表示一个小数呢?

不妨继续按照刚才思路进一步抽象
x = a n ∗ k n + ⋯ + a 1 ∗ k 1 + a 0 ∗ k 0 + a − 1 ∗ k − 1 + a − 2 ∗ k − 2 + ⋯ x = ∑ i = − ∞ n a i ∗ k i x=a_n*k^n+\cdots+a_1*k^1+a_0*k^0+\textcolor{red}{a_{-1}*k^{-1}+a_{-2}*k^{-2}+\cdots}\\ \textcolor{blue}{x=\sum_{i=-\infty}^{n}a_i*k^i} x=ankn++a1k1+a0k0+a1k1+a2k2+x=i=naiki

任意进制数到十进制的转换方法

通过观察我们发现上述和式就是一个把任意进制数转化为十进制的通用公式

例如:
0. A 8 ( 16 ) = 0 ∗ 1 6 0 + 10 ∗ 1 6 − 1 + 8 ∗ 1 6 − 2 = 0.6262 5 ( 10 ) 34. 5 ( 8 ) = 3 ∗ 8 1 + 4 ∗ 8 0 + 5 ∗ 8 − 1 = 28.62 5 ( 10 ) 0.A8_{(16)}=0*16^0+10*16^{-1}+8*16^{-2}=0.62625_{(10)}\\ 34.5_{(8)}=3*8^1+4*8^0+5*8^{-1}=28.625_{(10)} 0.A8(16)=0160+10161+8162=0.62625(10)34.5(8)=381+480+581=28.625(10)
数字右下脚标代表进制。

十进制转换为其它进制数

还是观察那个和式,我们发现对于 k k k进制数,如果能够找到每个 k i k^i ki前的系数 a i a_i ai,那么我们也就找到了这个数的 k k k进制表示。

下来就要分成整数部分小数部分来处理。

  • 整数部分,把 x x x的整数部分对 k k k取余数得到 a 0 a_0 a0,让 x x x除以 k k k,继续进行上述操作,直到 x x x的整数部分为0: a 0 = x % k , a 1 = ( x / k ) % k , ⋯ a_0=x\%k,a_1=(x/k)\%k,\cdots a0=x%k,a1=(x/k)%k,

    • 例:
      73.548 的 整 数 部 分 转 为 8 进 制 x = 73 a 0 = x % 8 = 1 ,   x = ⌊ x 8 ⌋ = 9 a 1 = x % 8 = 1 ,   x = ⌊ x 8 ⌋ = 1 a 2 = x % 8 = 1 ,   x = ⌊ x 8 ⌋ = 0 综 上 7 3 ( 10 ) = 1 ∗ 8 2 + 1 ∗ 8 1 + 1 ∗ 8 0 = 11 1 ( 8 ) 73.548的整数部分转为8进制\\ x = 73\\ a_0 = x \% 8 = 1,~ x=\lfloor\frac{x}{8}\rfloor= 9\\ a_1 = x \% 8 = 1,~ x=\lfloor\frac{x}{8}\rfloor= 1\\ a_2 = x \% 8 = 1,~ x=\lfloor\frac{x}{8}\rfloor= 0\\ 综上73_{(10)}=1*8^2+1*8^1+1*8^0=111_{(8)} 73.5488x=73a0=x%8=1, x=8x=9a1=x%8=1, x=8x=1a2=x%8=1, x=8x=073(10)=182+181+180=111(8)
  • 小数部分,让 x x x的小数部分乘以 k k k的取整到 a − 1 a_{-1} a1, 再对该乘后的结果的小数部分执行同样的操作得到 a − 2 ⋯ a_{-2}\cdots a2,重复执行。

    • 例:
      73.548 的 小 数 部 分 转 为 8 进 制 x = 0.548 a − 1 = ⌊ x ∗ 8 ⌋ = ⌊ 4.384 ⌋ = 4 ,   x = x ∗ 8 ( 取 小 数 部 分 ) = 0.384 a − 2 = ⌊ x ∗ 8 ⌋ = ⌊ 3.072 ⌋ = 3 ,   x = x ∗ 8 ( 取 小 数 部 分 ) = 0.072 a − 3 = ⌊ x ∗ 8 ⌋ = ⌊ 0.576 ⌋ = 0 ,   x = x ∗ 8 ( 取 小 数 部 分 ) = 0.576 a − 4 = ⌊ x ∗ 8 ⌋ = ⌊ 4.608 ⌋ = 4 ,   x = x ∗ 8 ( 取 小 数 部 分 ) = 0.608 ⋮ 73.548的小数部分转为8进制\\ x=0.548\\ a_{-1}=\lfloor x*8\rfloor=\lfloor4.384\rfloor=4,~x=x*8(取小数部分)=0.384\\ a_{-2}=\lfloor x*8\rfloor=\lfloor3.072\rfloor=3,~x=x*8(取小数部分)=0.072\\ a_{-3}=\lfloor x*8\rfloor=\lfloor0.576\rfloor=0,~x=x*8(取小数部分)=0.576\\ a_{-4}=\lfloor x*8\rfloor=\lfloor4.608\rfloor=4,~x=x*8(取小数部分)=0.608\\ \vdots 73.5488x=0.548a1=x8=4.384=4 x=x8()=0.384a2=x8=3.072=3 x=x8()=0.072a3=x8=0.576=0 x=x8()=0.576a4=x8=4.608=4 x=x8()=0.608
      我们发现在有些情况下小数有可能出现无限位的情况,这是正常的,这是进制本身的一种特性。
  • 综上 73.54 8 ( 10 ) = 111.4304 ⋯ ( 8 ) 73.548_{(10)}=111.4304\cdots_{(8)} 73.548(10)=111.4304(8)

快速的二进制,八进制,十六进制转化

首先,我们显然可将二进制先转为十进制,然后再用十进制转为八进制或十六进制

这里给出一种更好的做法:

思考一下,8进制下,一位能有几个数字,8个 ( 0 , ⋯   , 7 ) (0,\cdots,7) (0,,7),那么要用二进制来表示,其实也就是2的多少次方能表示这8个数字 2 x = 8 ⇒ x = log ⁡ 2 8 = 3 2^x=8 \Rightarrow x = \log_28=3 2x=8x=log28=3,也就是说我们只需用3个二进制位就可以表示8进制下的一位

例如:
11010100 1 ( 2 ) = 110   101   001 ( 拆 成 3 位 一 组 ) 其 中 110 ( 2 ) = 6 ( 8 ) ,   101 ( 2 ) = 5 ( 8 ) , 001 ( 2 ) = 1 ( 8 ) 所 以 : 110 101 001 ( 2 ) = 65 1 ( 8 ) 110101001_{(2)}=\textcolor{red}{110}~\textcolor{green}{101}~\textcolor{blue}{001}(拆成3位一组)\\ 其中 \textcolor{red}{110}_{(2)}=6_{(8)},~\textcolor{green}{101}_{(2)}=5_{(8)}, \textcolor{blue}{001}_{(2)}=1_{(8)}\\ 所以:\textcolor{red}{110}\textcolor{green}{101}\textcolor{blue}{001}_{(2)} = 651_{(8)} 110101001(2)=110 101 001(3)110(2)=6(8), 101(2)=5(8),001(2)=1(8)110101001(2)=651(8)
十六进制也是同理,只需将二进制拆成四个一组即可,因为 2 4 = 16 2^4=16 24=16

部分代码实现

  • 十进制转[2,16]之间的进制
// c++实现
/**
 * 该函数将10进制数转化为[2,16]进制数字的字符串表示, O(log(num))
 * @param num 10进制数字
 * @param k  转为k进制 2 <= k <= 16
 * @return k进制下数字字符串
 */
string dec2arbitrary(double num, int k) {
    assert(k >= 2 && k <= 16);
    char mp[] = {'0', '1', '2', '3',
                 '4', '5', '6', '7',
                 '8', '9', 'A', 'B',
                 'C', 'D', 'E', 'F'};
    string ret;
    // 处理整数部分
    {
        long n = (long) num;
        while (n > 0) {
            ret.push_back(mp[n % k]);
            n /= k;
        }
        std::reverse(ret.begin(), ret.end());
        ret.push_back('.');
    }
    // 处理小数部分
    {
        double x = num - (long) num;
        double dif = 1e-4; // 判断与0的接近程度
        // 由于小数部分有时有无穷位,所以我们一般要求精确到某位
        int bits = 10;
        for (int i = 0; i < bits && x > dif; i++) {
            x *= k;
            ret.push_back(mp[(long) x]);
            x -= (long) x;
        }
    }
    return ret;
}

习题

  • 尝试用和式的形式表示 768.445 768.445 768.445
  • 尝试将 3 F 3 F 转 为 10 进 制 。 3F3F转为10进制。 3F3F10
  • 尝试将 100101 转 为 10 进 制 。 100101转为10进制。 10010110
  • 尝试将 7562.03125 转 为 8 进 制 。 7562.03125转为8进制。 7562.031258
  • 尝试将 7562.03125 转 为 16 进 制 。 7562.03125转为16进制。 7562.0312516
  • 尝试将 10111011 转 为 8 进 制 。 10111011转为8进制。 101110118
  • 尝试将 10111011 转 为 16 进 制 。 10111011转为16进制。 1011101116
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值