最近在九度oj上看了幾個關於大數的問題,特意在這里總結一番。
要知道我們要將一個1000多位的十進制數轉換為二進制數,是沒有哪個類型能裝得下的,所以在這里我們的手動模擬輾轉相除法。實現將一個很長的十進制數字符串轉換成二進制的字符數組。
首先我們來看看這些int,long等等的取值范圍,明白它們到底可以存多大,我們才能放心到底什么時候可以用,什么時候不可以用。
數據類型名稱 | 字節數 | 別名 | 取值范圍 |
int | * | signed,signed int | 由操作系統決定,即與操作系統的"字長"有關 |
unsigned int | * | unsigned | 由操作系統決定,即與操作系統的"字長"有關 |
__int8 | 1 | char,signed char | –128 到 127 |
__int16 | 2 | short,short int,signed short int | –32,768 到 32,767 |
__int32 | 4 | signed,signed int | –2,147,483,648 到 2,147,483,647 |
__int64 | 8 | 無 | –9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
bool | 1 | 無 | false 或 true |
char | 1 | signed char | –128 到 127 |
unsigned char | 1 | 無 | 0 到 255 |
short | 2 | short int,signed short int | –32,768 到 32,767 |
unsigned short | 2 | unsigned short int | 0 到 65,535 |
long | 4 | long int,signed long int | –2,147,483,648 到 2,147,483,647 |
long long | 8 | none (but equivalent to __int64) | –9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
unsigned long | 4 | unsigned long int | 0 到 4,294,967,295 |
enum | * | 無 | 由操作系統決定,即與操作系統的"字長"有關 |
float | 4 | 無 | 3.4E +/- 38 (7 digits) |
double | 8 | 無 | 1.7E +/- 308 (15 digits) |
long double | 8 | 無 | 1.7E +/- 308 (15 digits) |
wchar_t | 2 | __wchar_t | 0 到 65,535 |
類型標識符 | 類型說明 | 長度 (字節) |
范圍 | 備注 |
char | 字符型 | 1 | -128 ~ 127 | -27 ~ (27 -1) |
unsigned char | 無符字符型 | 1 | 0 ~ 255 | 0 ~ (28 -1) |
short int | 短整型 | 2 | -32768 ~ 32767 | 2-15 ~ (215 - 1) |
unsigned short int | 無符短整型 | 2 | 0 ~ 65535 | 0 ~ (216 - 1) |
int | 整型 | 4 | -2147483648 ~ 2147483647 | -231 ~ (231 - 1) |
unsigned int | 無符整型 | 4 | 0 ~ 4294967295 | 0 ~ (232-1) |
float | 實型(單精度) | 4 | 1.18*10-38 ~ 3.40*1038 | 7位有效位 |
double | 實型(雙精度) | 8 | 2.23*10-308 ~ 1.79*10308 | 15位有效位 |
long double | 實型(長雙精度) | 10 | 3.37*10-4932 ~ 1.18*104932 | 19位有效位 |
具體的轉換思想(轉載):在數據結構課關於棧的這一章中,我們都學過用“模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才停止。
1 /*題目1138:進制轉換 2 題目描述: 3 將一個長度最多為30位數字的十進制非負整數轉換為二進制數輸出。 4 */ 5 #include "stdafx.h" 6 #pragma warning(disable:4996) 7 #include <stdio.h> 8 #include <cstring> 9 #include <string> 10 #include <iostream> 11 using namespace std; 12 char binvec[1001]; 13 14 15 void tenToBin(string str) 16 { 17 int j=0; 18 int sum=1; 19 int len=str.size(); 20 21 while (sum) 22 { 23 sum=0; 24 for (int i=0;i<len;++i) 25 { 26 int temp=(str[i]-'0')/2; 27 sum+=temp; 28 if (i==len-1) 29 { 30 binvec[j++]=(str[i]-'0')%2+'0'; 31 }else 32 { 33 str[i+1]=str[i+1]+(str[i]-'0')%2*10;//算出下一個被除數 34 } 35 //記錄該次得出的商 36 str[i]=temp+'0'; 37 } 38 } 39 40 41 } 42 void resout() 43 { 44 //逆序 45 int len1=strlen(binvec); 46 for (int i=0,j=len1-1;i<len1/2;++i,--j) 47 { 48 char temp=binvec[j]; 49 binvec[j]=binvec[i]; 50 binvec[i]=temp; 51 } 52 cout<<binvec<<endl; 53 } 54 int main() 55 { 56 string str; 57 while(cin>>str) 58 { 59 memset(binvec,'\0',sizeof(binvec)); 60 tenToBin(str); 61 resout(); 62 } 63 return 0; 64 }