大数问题(高精度运算)
生活随笔
收集整理的這篇文章主要介紹了
大数问题(高精度运算)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、基本概念
在某些情況下,我們必須處理相當大的一個整數,運用類型int、long int、long long int 類型均無法對其進行存儲。要解決這樣的問題,我們就需要自己編寫相應的處理程序。在處理大數的時候,可以將其作為字符串讀入,然后一個數字一個數字的存儲到數組中,然后編寫相應運算操作的處理函數即可解決大數問題。
也就是說在對大數進行運算之前,要先解決對大數進行存儲的問題。而這里一一般情況為例,對輸入和輸入函數進行定義。
輸入處理:
輸入字符串:
| c[0] | c[1] | c[2] | c[3] | c[4] | c[5] | c[6] | c[7] | c[8] | c[9] |
| '1' | '2' | '3' | '3' | '4' | '5' | '6' | x | x | x |
轉換為對應數字存儲:
| ans[0] | ans[1] | ans[2] | ans[3] | ans[4] | ans[5] | ans[6] | ans[7] | ans[8] | ans[9] |
| 6 | 5 | 4 | 3 | 3 | 2 | 1 | 0 | 0 | 0 |
反向存儲好處:
對大數進行存儲以后,是為了要對其進行運算處理。而后的運算有可能會增加數字的位數,如果正向存儲的話在出現有進位的情況時則需要將數組整體進行右移然后加入新產生的進位。如果對對大數進行方向存儲的話,在運算過程中產生的進位可以直接加到足夠大的數組后邊,而只需改變數組長度即可,無需進行移位操作,這樣一來就方便多了,運算處理完后只需要反向輸出結果即可。
#include<stdio.h>#include<string.h> #define LEN 500 /*輸入函數參數:ans 輸入的大數組len 帶回大數的位數,也就是數組的長度返回:是否輸入成功,0:否,1:是函數說明:1、按字符串形式輸入大數2、反向單個數字存入到ans數組中*/ int Input(int* ans,int &len) {
char c[LEN];
int i,j;
if(scanf("%s",&c)<0)return 0;
len = strlen(c);
for( i=len-1,j=0; i>=0; i--,j++)
{
ans[j] = c[i];
}
return 1 }/*輸入函數參數:ans 需要輸出的大數組len 數組的長度函數說明:反向輸入大數數組*/void Output(int* ans,int &len) {int i;
for( i=len-1; i>=0; i--)
printf("%d",ans[i]);
printf("\n"); }int main() {int ans[LEN],len;
memset(ans,0,sizeof(ans));Input(ans,len);Output(ans); return 0; }
?二、相關例子
以下是一些有關大數處理的例子,題目來自于南洋理工學院的ACM評測系統,均已通過測評。
2.1 大整數相加
/* 描述 I have a very simple problem for you. Given two integers A and B, your job is to calculate the Sum of A + B. A,B must be positive.輸入 The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line consists of two positive integers, A and B. Notice that the integers are very large, that means you should not process them by using 32-bit integer. You may assume the length of each integer will not exceed 1000.輸出 For each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line is the an equation "A + B = Sum", Sum means the result of A + B. Note there are some spaces int the equation.
樣例輸入 2 1 2 112233445566778899 998877665544332211
樣例輸出 Case 1: 1 + 2 = 3 Case 2: 112233445566778899 + 998877665544332211 = 1111111111111111110*/#include<stdio.h> #include<string.h>#define LEN 1000+10 /*輸入處理函數參數:char* in : 未經處理的字符串數組char* out : 經過處理存儲后的數組返回:返回out數組長度 */ int Change(char* in,char* out) {int i,j,len;memset(out,0,LEN);len = strlen(in);for( i=len-1,j=0; i>=0; j++,i--){out[j] = in[i]-'0';}return len; } /*輸出函數參數:char* ans1 : 加數char* ans2 : 加數char* result : ans1 + ans2 的結果int len1 : ans1的長度int len2 : ans2的長度int len3 : result的長度 */ void Output(char* ans1,char* ans2,char* result,int len1,int len2,int len3) {int i;for( i=len1-1; i>=0; i--)printf("%d",ans1[i]);printf(" + ");for( i=len2-1; i>=0; i--)printf("%d",ans2[i]);printf(" = ");for( i=len3-1; i>=0; i--)printf("%d",result[i]);putchar('\n'); }/*加法操作函數參數:char* ans1 : 加數char* ans2 : 加數char* result : ans1 + ans2 的結果int len1 : ans1的長度int len2 : ans2的長度int len3 : 帶回result的長度 */ void Add(char* ans1,char* ans2,char* result,int len1,int len2,int &len3) {int i,len;memset(result,0,LEN);len = len1>len2?len1:len2;for(i=0; i<len; i++){result[i] += ans1[i] + ans2[i];if( result[i]>=10)//參數進位 {result[i+1] += result[i]/10;result[i] = result[i]%10;}}if(result[len]!=0)len++;len3 = len; }int main() {//輸入輸出重定向//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);char in1[LEN],in2[LEN],ans1[LEN],ans2[LEN],result[LEN];int len1,len2,len3,n,i;scanf("%d",&n);i=1;while(n--){scanf("%s%s",&in1,&in2);len1 = Change(in1,ans1);len2 = Change(in2,ans2);Add(ans1,ans2,result,len1,len2,len3);printf("Case %d:\n",i++);Output(ans1,ans2,result,len1,len2,len3);}return 1; }
?
2.2 大整數相乘
/* POJ 2389DescriptionBulls are so much better at math than the cows. They can multiply huge integers together and get perfectly precise answers ... or so they say. Farmer John wonders if their answers are correct. Help him check the bulls' answers. Read in two positive integers (no more than 40 digits each) and compute their product. Output it as a normal number (with no extra leading zeros). FJ asks that you do this yourself; don't use a special library function for the multiplication. Input* Lines 1..2: Each line contains a single decimal number. Output* Line 1: The exact product of the two input lines Sample Input11111111111111 1111111111 Sample Output12345679011110987654321*/#include<stdio.h> #include<string.h>#define LEN 200+10/*輸入處理函數參數:int* ans : 經過處理后的反序大數數組返回:ans的長度,既大數的位數 */ int Input(int* ans) {char in[LEN];int i,j,len;scanf("%s",&in);len = strlen(in);for( i=len-1,j=0; i>=0; i--,j++){ans[j] = in[i]-'0';}return len; }/*輸出處理函數:參數:int* ans : 需要輸出的大數數組 */ void Output(int* ans) {int i;for(i=LEN*2; ans[i]==0 && i>=0; i--);if(i<0){printf("0\n");return;}for(; i>=0; i--)printf("%d",ans[i]);printf("\n"); }/*乘法操作函數參數:int* ans1 : 乘數int* ans2 : 乘數int* result : ans1 * ans2 的結果int len1 : ans1的長度int len2 : ans2的長度 */ void Mul(int* ans1,int* ans2,int* result,int len1,int len2) {int i,j;for( i=0; i<len1; i++ ){for( j=0; j<len2; j++){result[i+j] += ans1[i]*ans2[j];}}for(i=0; i<2*LEN-1; i++)//處理進位 {if(result[i]>=10){result[i+1] += result[i]/10;result[i] = result[i] % 10;}} } int main() {freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);int ans1[LEN]={0},ans2[LEN]={0},result[2*LEN]={0},len1,len2;len1 = Input(ans1);len2 = Input(ans2);Mul(ans1,ans2,result,len1,len2);Output(result);return 1; }?
2.3 大整數相除
/*南陽:題目803描述做了A+B Problem,A/B Problem不是什么問題了吧!輸入 每組測試樣例一行,首先一個號碼A,中間一個或多個空格,然后一個符號( / 或者 % ),然后又是空格,后面又是一個號碼B,A可能會很長,B是一個int范圍的數。 輸出 輸出結果。 樣例輸入 110 / 100 99 % 10 2147483647 / 2147483647 2147483646 % 2147483647 樣例輸出 1 9 1 2147483646解題思路: 基本的思想是反復做減法,看看從被除數里最多能減去多少個除數,商就是多少。一個一個減顯然太慢,如何減得更快一些呢?以7546 除以23 為例來看一下:開始商為0。先減去23 的100 倍,就是2300,發現夠減3 次,余下646。于是商的值就增加300。然后用646 減去230,發現夠減2 次,余下186,于是商的值增加20。最后用186 減去23,夠減8 次,因此最終商就是328。所以本題的核心是要寫一個大整數的減法函數,然后反復調用該函數進行減法操作。 計算除數的10 倍、100 倍的時候,不用做乘法,直接在除數后面補0 即可。*/ #include<stdio.h> #include<string.h>#define LEN 1000 /*輸入處理函數參數:int* divisor : 被除數int* dividend : 除數char &c : 帶會操作符int &dslen : 被除數長度int &delen : 除數長度返回:是否輸入結束,0:是,1:否 */ int Input(int* divisor,int* dividend,char &c,int &dslen,int &delen) {char in1[LEN],in2[2],in3[LEN];int i,j,k;if (scanf("%s%s%s",&in1,&in2,&in3)==EOF)return 0;c = in2[0];dslen = strlen(in1);delen = strlen(in3);for( k=0; k<dslen-1 && in1[k]=='0'; k++);//處理前導數0,最后一個數不用檢查,因為最后一個數無論是0還是非零都需要存儲for( j=0,i=dslen-1; i>=k; j++,i--)divisor[j] = in1[i] - '0';dslen -= k;for( k=0; k<delen-1 && in3[k]=='0'; k++);////處理前導數0,最后一個數不用檢查for( j=0,i=delen-1; i>=k; j++,i--)dividend[j] = in3[i] - '0';delen -=k;return 1; }/*減法操作函數參數:int* ans1 : 被減數,并且勇于帶回相減的結果int* ans2 : 減數int len1 : 被減數長度int len2 : 減數長度返回值-1 : 被減數小于減數a>=0 : 所求結果ans1的長度 */ int Sub(int* ans1,int* ans2,int len1,int len2) {int i,j;//以下判斷ans1是否大于ans2,不大于則返回-1if( len1<len2 )return -1;else if(len1 == len2){for( i=len1-1; i>=0; i-- ){if(ans1[i]<ans2[i])return -1;else if(ans1[i]>ans2[i])break;}}for( i=0; i<len1; i++){//要求調用本函數時確保黨i>=len2時,ans2[i] = 0ans1[i] -= ans2[i];if( ans1[i]< 0)//借位 {ans1[i] += 10;ans1[i+1]--;}}for( i=len1-1; i>=0 && ans1[i]==0; i--);//去掉前導0return i+1;}void Output(int* ans,int len) {int i;for(i=len-1; i>=0; i--)printf("%d",ans[i]);printf("\n"); }int main() {freopen("in.txt","r",stdin);freopen("out.txt","w",stdout);int divisor[LEN],dividend[LEN],result[LEN],len1,len2,len3;char operate;while(1){memset(divisor,0,sizeof(divisor));memset(dividend,0,sizeof(dividend));if( Input(divisor,dividend,operate,len1,len2) == 0 )break;//如果被除數小于除數可以直接得到結果if( len1 < len2){if( operate == '/' )printf("0\n");else if(operate == '%')Output(divisor,len1);continue;}int Times = len1 - len2;//被除數比除數多幾位int i;if(Times>0)//減數低位補0 {for( i=0; i<len2; i++)dividend[i+Times] = dividend[i];for(i=0; i<Times; i++)dividend[i] = 0;len2 = len1;}int temp;memset(result,0,sizeof(result));for(i=0; i<=Times; i++){//一直減到不夠減為止//先減去若干個 dividend×(10 的 Times 次方),//不夠減了,再減去若干個 dividend×(10 的 Times-1 次方),......while((temp = Sub(divisor,dividend+i,len1,len2-i))>=0){len1 = temp;result[Times-i]++;}}if(operate == '/'){for(i=LEN-1; i>=0 && result[i]==0; i--);Output(result,i+1);}else if(operate == '%'){for(i=LEN-1; i>=0 && divisor[i]==0; i--);Output(divisor,i+1);}}return 0; }?
轉載于:https://www.cnblogs.com/fanling999/p/3931645.html
總結
以上是生活随笔為你收集整理的大数问题(高精度运算)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACM 中常用的算法有哪些?
- 下一篇: 无法解析此远程名称: 'www.***.