C語言程序設計100例之(24):數制轉換


例24   數制轉換

題目描述

請你編一程序實現兩種不同進制之間的數據轉換。

輸入格式

共三行,第一行是一個正整數,表示需要轉換的數的進制n(2≤n≤16),第二行是一個n進制數,若n>10則用大寫字母A-F表示數碼10-15,並且該n進制數對應的十進制的值不超過1000000000,第三行也是一個正整數,表示轉換之后的數的進制m(2≤m≤16)。

輸出格式

一個正整數,表示轉換之后的m進制數。

輸入樣例

16

FF

2

輸出樣例

11111111

        (1)編程思路。

        十進制整數轉換為R進制整數的基本方法是:“除R取余”。具體做法為:對於十進制數整數,用R連續除要轉換的十進制整數及各次所得之商,直除到商等於0時為止,則各次所得之余數即為所求R進制整數由低位到高位的值。這個過程可以寫成一個簡單的循環。

        一般而言,對於任意的R進制數 An-1An-2…A1A0可以表示為以下和式:

         An-1×Rn-1 +…+A1×R1+A0×R0 (其中R為基數)

        這個和式也稱為“按權展開式”。

        R進制數轉換為十進制數的基本方法是將R進制數的各位按權展開相加即可。

        本例的思路是:將輸入的n進制整數按權值展開后轉換為十進制整數,再將所得的十進制整數采用“除m取余”轉換為m進制整數即可。

        (2)源程序。

#include <stdio.h>

int main()

{

    char table[17]="0123456789ABCDEF";

    int n,m;

    char s[33];

    scanf("%d",&n);

    scanf("%s",s);

    scanf("%d",&m);

    int num=0;

    for (int i=0;s[i]!='\0';i++)     // n進制整數按權值展開后轉換為十進制整數num

    {

        if (s[i]>='0' && s[i]<='9')

            num=num*n+s[i]-'0';

        else

            num=num*n+s[i]-'A'+10;

    }

    int digit[32],cnt=0;

    do {                   // 十進制整數采用“除m取余”轉換為m進制整數

        digit[cnt++]=num%m;

        num=num/m;

    } while (num!=0);

    for (int i=cnt-1;i>=0;i--)

        printf("%c",table[digit[i]]);

    printf("\n");

    return 0;

}

習題24

24-1  高低位交換

        本題選自洛谷題庫 (https://www.luogu.org/problem/P1100)。

題目描述

給出一個小於232的正整數。這個數可以用一個32位的二進制數表示(不足32位用0補足)。我們稱這個二進制數的前16位為“高位”,后16位為“低位”。將它的高低位交換,我們可以得到一個新的數。試問這個新的數是多少(用十進制表示)。

例如,數1314520用二進制表示為00000000000101000000111011011000(添加了11個前導0補足為32位),其中前16位為高位,即0000000000010100;后16位為低位,即0000111011011000。將它的高低位進行交換,我們得到了一個新的二進制數00001110110110000000000000010100。它即是十進制的249036820。

輸入格式

一個小於232的正整數。

輸出格式

將新的數輸出

輸入樣例

1314520

輸出樣例

249036820

        (1)編程思路。

        將輸入的十進制整數采用“除2取余”轉換為二進制整數,再將所得的二進制整數依照低16位在前高16位在后的方式按權值展開后轉換為十進制整數即可。

        (2)源程序。

#include <stdio.h>

int main()

{

    unsigned int num;

    scanf("%d",&num);

    int digit[32]={0},cnt=0;

    do {                   // 十進制整數采用“除2取余”轉換為二進制整數

        digit[cnt++]=num%2;

        num=num/2;

    } while (num!=0);

    int i;

    for (i=15;i>=0;i--)            // 先將低16位按權值展開

        num=num*2+digit[i];

    for (i=31;i>=16;i--)           // 再將高16位按權值展開

        num=num*2+digit[i];

    printf("%u\n",num);

    return 0;

}

24-2  進制轉換

        本題選自洛谷題庫 (https://www.luogu.org/problem/P1017)。

題目描述

一般說來,任何一個正整數R或一個負整數-R都可以被選來作為一個數制系統的基數。如果是以R或-R為基數,則需要用到的數碼為 0,1,....R-1。例如,當R=7時,所需用到的數碼是0,1,2,3,4,5和6,這與其是R或-R無關。如果作為基數的數絕對值超過10,則為了表示這些數碼,通常使用英文字母來表示那些大於9的數碼。例如對16進制數來說,用A表示10,用B表示11,用C表示12,用D表示13,用E表示14,用F表示15。

在負進制數中是用-R作為基數,例如-15 (十進制)相當於110001 (-2進制),並且它可以被表示為2的冪級數的和數:

110001=1×(−2)5 +1×(−2)4 +0×(−2)3 +0×(−2)2 +0×(−2)1 +1×(−2)0

設計一個程序,讀入一個十進制數和一個負進制數的基數,並將此十進制數轉換為此負進制下的數:-R∈{-2,-3,-4,...,-20}

輸入格式

輸入包括多組測試數據。

每組測試數據占一行,每行有兩個輸入數據。

第一個是十進制數N (−32768≤N≤32767)

第二個是負進制數的基數-R。

輸出格式

結果顯示在屏幕上,相對於輸入,應輸出此負進制數及其基數,若此基數超過10,則參照16進制的方式處理。

輸入樣例

30000 -2

-20000 -2

28800 -16

-25000 -16

輸出樣例

30000=11011010101110000(base-2)

-20000=1111011000100000(base-2)

28800=19180(base-16)

-25000=7FB8(base-16)

        (1)編程思路。

        我們知道十進制整數是采用“除R取余”轉換為R進制整數的,對於負基數(-R)同樣如此。

        先看問題描述中的例子-15轉換為-2進制數。在C語言中“除R取余”運算過程為:

被除數

除數

余數

-15

-2

7

-1

7

-2

-3

1

-3

-2

1

-1

1

-2

0

1

        這里余數出現了負數,需要將余數轉換成正數,怎么處理呢?

        因為, 被除數=商*除數+余數=商*除數+除數+余數-除數=(商+1)*除數+(余數-除數)。因此,若余數為負時,只需要將商+1,余數-除數,就可以將余數轉換為正數。

被除數

除數

余數

校正的商

校正余數

-15

-2

7

-1

8

1

8

-2

-4

0

 

 

-4

-2

2

0

 

 

2

-2

-1

0

 

 

-1

-2

0

-1

1

1

1

-2

0

1

 

 

         因此,-15轉換為-2進制數為110001。

         (2)源程序。

#include <stdio.h>

int main()

{

    char table[21]="0123456789ABCDEFGHIJ";

    int num,r;

    while (scanf("%d%d",&num,&r)!=EOF)

    {

        printf("%d=",num);

        int digit[32]={0},cnt=0;

        do {

           int t=num%r;

           num=num/r;

           if (t<0) {t=t-r; num++; }

           digit[cnt++]=t;

        } while (num!=0);

        int i;

        for (i=cnt-1;i>=0;i--)

          printf("%c",table[digit[i]]);

        printf("(base%d)\n",r);

    }

    return 0;

}

24-3  彩燈和按鈕

問題描述

有一個機器,它有 m(2≤m≤30) 個彩燈和一個按鈕。每按下按鈕時,最右邊的彩燈會發生一次變換。變換為:①如果當前狀態為紅色,它將變成綠色;②如果當前狀態為綠色,它將變成藍色;③如果當前狀態為藍色,它將變成紅色,並且它左邊的彩燈(如果存在)也會發生一次變換。初始狀態下所有的彩燈都是紅色的。

輸入格式

輸入包括多組測試,第1行給出正整數T(1≤T≤15),表示測試數據的組數。

每組測試數據包括兩個整數m(2≤m≤30) 和 n(1≤n<263),分別表示彩燈的個數和按鈕被按下的次數。

輸出格式

對每組測試數據,按從左到右的順序輸出各彩燈的顏色狀態,R 表示紅色,G表示綠色,B 表示藍色。

輸入樣例

2

3 1

2 3

輸出樣例

RRG

GR

        (1)編程思路。

        每按一次按鈕都是從最右邊的彩燈開始變換,將m個彩燈可以看成一個m位數,最右邊的彩燈為其個位數,每按一次按鈕可以看成個位數加1。每按三次后從右數第二個彩燈才會變一下,每按9次從右邊數第三個彩燈會變換一次,……。

        顯然,m個彩燈表示的m位數可以看成是一個三進制數,紅燈表示0,綠燈表示1,藍燈表示2,將輸入的n轉換為3進制數即可。

        (2)源程序。

#include <stdio.h>

#include <string.h>

int main()

{

    char table[4]="RGB";

    int t, m, len;

    long long n;

    int color[30];

    scanf("%d", &t);

    while(t--)

    {

        memset(color, 0, sizeof(color));

        scanf("%d%lld", &m, &n);

        len = m;

        while (n > 0 && m > 0)

        {

            color[--m] = n % 3;

            n /= 3;

        }

        for (int i=0; i<len; i++)

            putchar(table[color[i]]);

        putchar('\n');

    }

   return 0;

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM