高精度的進制轉換

轉載自:http://www.cppblog.com/kuangbin/archive/2011/08/25/154299.html

高精度的進制轉換


前面的內容來源於:http://www.cnblogs.com/phinecos/archive/2009/09/11/1564975.html

引用原文:

在數據結構課關於棧的這一章中,我們都學過用2取餘法來將一個10進制數轉換爲一個二進制數,進而可以推廣到n取餘法,經其轉換爲n進制(n任意指定)。

確實,這是一個很基礎的題目,可你是否想過如果這個10進制數是一個大數(其位數可能上千位,此時用一般數據類型肯定是會溢出的),那麼這個問題又如何來求解呢?

當然,也許你會說很簡單嘛,自己寫一個大數類(當然至少要寫一個大數除法才行),或者你用的是Java這種現代化語言,就更輕鬆了,直接用BigInteger這樣的大數類就可以來表示一個大數,進而用書上教的方法來實現。

但是,真的需要用到大數類嗎?事實上,殺雞焉用牛刀,我們在紙上模擬一番上述運算後就可以發現,只要做一些小小的改進,就可以在不使用大數的情況下,也可以通過n取餘的原理來實現大數的進制轉換的。(當然,整體的思想仍然是n取餘原理!!!)。

舉個簡單的例子,就比如說把10進制數12轉換爲2進制形式,書上的方法可以用下圖來表示

按照 “先餘爲低位,後餘爲高位這條鐵律,其結果爲1100.

這是書上教我們的常規思路(可惜按這個的話,大數是沒法考慮的,因爲假如這裏不是12,而是一個1000位的大數,由於是是對大數的整體進行取餘運算,不使用大數類及其除法操作,又如何得以進行呢?),可我們的目的是不使用大數類,那麼現在我們就來換一個視角來看這個問題,12是一個十位數,十位上是1,個位上是2,按照我們正常的思維來看,這個計算應該是下面這樣的:


那麼我們發現在第一輪運算時,十位上的1作爲被除數,2作爲除數,得到的商是0,餘數是1(可以斷言只考慮當前這一個數位的計算,餘數或是0,或是1,若是1的話,則進入下一數位(這裏即對個位進行運算)時,要用1乘上進制(這裏是10)再加上下一個數位上的值(這裏是2),即得到運算進入個位時被除數是12,除數是2,得到的商是6,餘數是0。第一輪運算的結果是商是06,餘數是0.

進入第二輪運算,則上一輪的商6(這裏首先要去掉前面多餘的0)變成本輪的被除數,如此下去,即可得到每輪的餘數。

推廣開來,如果被除數是一個1000位的大數,例如“12343435154324123……342314324343”

那麼我們照樣可以從第一個數位開始逐位考慮,比如第一位是1(作爲被除數),2是除數,得到的商是0,餘數是1,然後是第二個數位2,由於上一位留下了餘數1,則此時被除數應該是1*10+2 = 12,所以得到的商是6,餘數是0,即運算到此時的商是06,然後是第三個數位3,由於上一個數位留下的餘數是0,所以此時被除數就是3,。。。如此下去就完成第一輪的運算,

這一輪完畢後,需要把得到的商變成下一輪的被除數,繼續上述的運算,直到被除數爲0才停止。

下面給出了一個示例代碼,展示瞭如何將一個10進制的大數轉換爲其二進制形式,僅供參考:

#include <stdio.h>
#include <string.h>

char str[1000];//輸入字符串
int start[1000],ans[1000],res[1000]; //被除數,商,餘數

//轉換前後的進制
const int oldBase = 10;
const int newBase = 2;

void change()
{//各個數位還原爲數字形式
    int i,len = strlen(str);
    start[0] = len;
    for(i=1;i<= len;i++)
    {
        if(str[i-1] >= '0' && str[i-1] <= '9')
        {
            start[i] = str[i-1] - '0';
        }
    } 
}

void solve()
{
    memset(res,0,sizeof(res));//餘數初始化爲空
    int y,i,j;
    //模n取餘法,(總體規律是先餘爲低位,後餘爲高位)
    while(start[0] >= 1)
    {//只要被除數仍然大於等於1,那就繼續“模2取餘”
        y=0;
        i=1;
        ans[0]=start[0];
        //
        while(i <= start[0])
        {
            y = y * oldBase + start[i];
            ans[i++] = y/newBase;
            y %= newBase; 
        }
        res[++res[0]] = y;//這一輪運算得到的餘數
        i = 1;
        //找到下一輪商的起始處
        while((i<=ans[0]) && (ans[i]==0)) i++;
        //清除這一輪使用的被除數
        memset(start,0,sizeof(start));
        //本輪得到的商變爲下一輪的被除數
        for(j = i;j <= ans[0];j++)
            start[++start[0]] = ans[j]; 
        memset(ans,0,sizeof(ans)); //清除這一輪的商,爲下一輪運算做準備
    } 
}

void output()
{//從高位到低位逆序輸出
    int i;
    for(i = res[0];i >= 1;--i)
    {  
        printf("%d",res[i]);
    }
    printf("\n"); 
}

int main()
{
    scanf("%s",str);
    change();
    solve();
    output();
    return 0;
}

個人根據POJ1220,總結高精度的N進制轉換模板如下:

/*
高精度進制轉換 
把oldBase 進制的數轉化爲newBase 進制的數輸出。
調用方法,輸入str, oldBase newBase.
change();
solve();
output();
也可以修改output(),使符合要求,或者存入另外一個字符數組,備用 
*/
#include<stdio.h>
#include<string.h>
#defien MAXSIZE 1000
char str[MAXSIZE];//輸入字符串
int start[MAXSIZE],ans[MAXSIZE],res[MAXSIZE];//被除數,商,餘數
int oleBasw,newBase;//轉換前後的進制

//單個字符得到數字
int getNum(char c)//這裏進制字符是先數字,後大寫字母,後小寫字母的 
{
    if(c>='0'&&c<='9') return c-'0';//數字 
    if(c>='A'&&c>='Z') return c-'A'+10;//大寫字母 
    return c-'a'+36;//小寫字母 
}    
//數字得到字符
char getChar(int i)
{
    if(i>=0&&i<=9)return i+'0';
    if(i>=10&&i<=35)return i-'10'+'A';
    return i-36+'a';
}     
void change()//把輸入的字符串的各個數位還原爲數字形式
{
    int i;
    start[0]=strlen(str);//數組的0位存的是數組長度
    for(i=1;i<=start[0];i++)
        start[i]=getNum(str[i-1]); 
}    
void solve()
{
    memset(res,0,sizeof(res));//餘數位初始化爲空
    int y,i,j;
    while(start[0]>=1) 
    {
        y=0;i=1;
        ans[0]=start[0];
        while(i<=start[0])
        {
            y=y*oldBase+start[i];
            ans[i++]=y/newBase;
            y%=newBase;
        }    
        res[++res[0]]=y;//這一輪得到的餘數
        i=1;//找下一輪商的起始處,去掉前面的0
        while(i<=ans[0]&&ans[i]==0) i++;
        memset(start,0,sizeof(start));
        for(j=i;j<ans[0];j++)
           start[++start[0]]=ans[j];
        memset(ans,0,sizeof(ans)); 
    }    
}  
void output()//從高位到低位逆序輸出 
{
    int i;
    for(i=res[0];i>=1;i--)
        printf("%d",getChar(res[i]));
    printf("\n");
} 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章