进制转换及原理

 

contents:

1)任意进制转化为10进制

2)10进制转换为任意进制

3)大数任意进制转化

 

一.任意进制转化为10进制:

     原理:

     这个最好理解。首先要知道:不同数位的权重不同

     以一个十进制数186为例:

    个位上的6代表的值是6×{10}^{0},即6;

    十位上的8代表的值其实是8×{10}^{1},即80;

     百位的1同理代表1×10^{2},即100;

     可见不同数位上,即便数字相同,其所代表的值也不同,这就是权重的含义。

     

     再以一个二进制数1111为例:

     最低位的1代表的值是1×2^{0},即1;

     第二位的1代表的是1×2^{1},即2;

     第三位的1代表的值是1×2^{2},即4;

     第四位的1代表的值是1×2^{3},即8;

     同样是1,但因为所处数位不同,其所代表的数值也不同。

 

     要将上述的1111转化为十进制很简单:

     首先如上计算出各个数位上的数的真实数值。

     二进制不像我们熟悉的十进制那么直观。比如186这个数,十位上的8我一眼就能知道它代表的是80;其他进制则需要我们通过计算得到各个数位上真实的值,如二进制下1111的四个1真实数值分别为1,2,4,8;

     再求和即得其十进制的表示法:1+2+4+8=15;

     

     二进制的1111和十进制的15在数值上其实是一样的,但是因为采用了不同的进制所以表示方法不同;

     1×2^{0}+1×2^{1}+1×2^{2}+1×2^{3}=1×10^{1}+5×10^{0}

 

     从上例我们就可以看出将任意进制转化为10进制的方法;

     根据每个数位的权重,算出该数位上的数实际表示的值,然后求和

     比如十六进制数1E(十六进制中E表示14):

     (1E)_{16}=1×16^{1}+14×16^{0}=(30)_{10}

 

     可以发现,在任一进制下,随着数位的增加,其权重必然也会增加。而不同进制的区别可能就在于,它们权重随数位的递增量不同。

    

     下附十六进制转十进制代码:

long long base_conversion(char s[]){
    long long base=1;
    long long ret=0;
    for(int i=strlen(s)-1;i>=0;i--){
        if(s[i]>='A'&&s[i]<='F')
            ret+=((s[i]-'A'+10)*base);
        else
            ret+=(s[i]-'0')*base;
        base*=16;
    }
    return ret;
}

int main()
{
    char s[10];//因为十六进制数可能含A~F,所以用字符串来存储十六进制数
    cin>>s;
    cout<<base_conversion(s);
    return 0;
}

 

二.10进制转换为任意进制

   除数取余法(模n取余法):

   以将十进制的12转化为二进制为例:

   1)          12%2=0 ………………0

   2)12/2=6 6%2=0 ………………0

   3) 6/2=3  3%2=1 ………………1

   4) 3/2=1  1%2=1 ………………1

   5) 1/2=0   

   所以12的二进制表示就是1100

   

    将十进制的30转化为八进制:

    1)            30%8=6………………6

     2)30/8=3 3%8= 3………………3

     3)3/8=0

     所以30的八进制表示就是36

   

    原理

    一个任意的整数 都可以表示以10为底的幂组成的多项式:

    例:386=3×10^{2}+8×10^{1}+6×10^{0};     42=4×10^{1}+2×10^{0}

    不难发现,10的k次幂前的系数就是原数第k+1位上的数

   

    而以386=3×10^{2}+8×10^{1}+6×10^{0}=10×(3×10^{1}+8)+6为例

    可以看到我们对386除以10后得到的余数就是其个位上的数字6

    因为除了以6为系数的这一项,其他项起码含一个10的因子。

 

    根据这个定理,我们只要对一个整数不断地除以10,然后用商做下一次运算的被除数就可以得到这个整数个位,十位,百位……上的数字

     

     同样的,一个任意的整数 也可以表示为以2为底的幂组成的多项式:

      例:137=1×2^{7}+0×2^{6}+0×2^{5}+0×2^{4}+1×2^{3}+0×2^{2}+0×2^{1}+1×2^{0}

      由这个多项式可直接得到137的二进制表示:10001001

      和10进制一样,除了最低位,其他项都是2的倍数,我们对137除以2得到的余数就是其最低位上的数字。

      所以我们只要对一个整数除以2取余数,再不断取商做下一次运算即得其二进制表示;   

    

     其他进制也都是一样的(下以十进制转十六进制为例):

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int x,cnt=0;
    char ans[10];
    cin>>x;
    while(x){
        int temp=x%16;
        if(temp<=9)
            ans[cnt++]=temp+'0';
        else
            ans[cnt++]=temp-10+'A';
        x/=16;
    }
    if(cnt==0)
        cout<<'0';
    for(int i=cnt-1;i>=0;i--)
        cout<<ans[i];
    return 0;
}

 

三.大数任意进制的转换

      任意进制转换其实很简单,因为我已经写了任意进制转十进制以及十进制转任意进制的办法;所以我们只要以十进制为中介,就能实现任意进制的转换。

       难点就在大数上。

       当一个数字过大时,C语言中我们只能用字符串来存储它。

       这在计算上带来了很大的麻烦。

       一个任意进制转换为十进制需要大量的大数乘法和大数求和;

       而十进制转换为任意进制更难,需要做很多大数的取模运算。

       我们可以使用高精度计算来解决,在某些情况下却也有更简便的方法。

       下以十六进制转换为八进制来举例:

       在将十六进制转换为八进制时,我们可以用二进制作为媒介,它相比之前讲过的方法更简单。

       1)将十六进制转换为二进制

       将每个十六进制的数,转换为一个四位的二进制数即可。

       比如7转换为0111,A转换为1010。

      那么十六进制的7A转换为二进制就是01111010,再去掉前导0即可。

       2)将二进制转换为八进制

      从低位开始,不断取三位二进制数合成一个八进制数,其实相当于上述运算的逆运算。

      比如上面的1111010:

      先取低位的三个数字010,转换为八进制即2。

      再取111,转换为八进制即7。

      最后不足三位了,只剩一个1,看成001即可,转换为八进制即1。

      结果:172。

      经验算可得十六进制的7A,二进制的1111010,八进制的172表达的数值都是相同的,即十进制的122。

      下附代码(用到了双向队列deque):

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string s;
    cin>>s;//读入十六进制数
    deque<int>q,ans;
    for(int i=0;i<s.size();i++){//逐位计算
        int temp;//temp用于计算每位十六进制数对应的十进制表达
        if(s[i]>='0'&&s[i]<='9')   temp=s[i]-'0';
        else                    temp=s[i]-'A'+10;
        
        //再将十进制转换为二进制,模二取余法即可
        int a[4];
        for(int cnt=3;cnt>=0;cnt--){
               a[cnt]=temp%2;
               temp/=2;
        }
        //再将结果存入双向列表q中
        for(int i=0;i<4;i++)
               q.push_back(a[i]);
    }
    //以上实现了十六进制到二进制的转换
    
    while(!q.empty()){
          int num;//num表示要取的个数
          q.size()<3?(num=q.size()):(num=3);
          //最后不足三位时,还剩几位取几位

          int temp=0,t=1;
          for(int i=0;i<num;i++){
                temp+=(q.back()*t);
                q.pop_back();
                t*=2;
          }
          //用temp存储,转化为了八进制
          ans.push_front(temp);//存入答案
       }

       if(ans.front()==0)//如果含有前导0要去掉
             ans.pop_front();
       while(!ans.empty()){
          cout<<ans.front();
          ans.pop_front();
       }
       cout<<endl;
    }

    return 0;
}

       

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值