大數(高精度)問題 【一】
阿新 • • 發佈:2019-02-04
處理大數問題為什麼用字串陣列接收資料又轉存到整型陣列?
整型陣列接收單個數字是以空格或者回車作為結束符,大整數的輸入過程是沒有空格或回車的。字串陣列實際儲存的是一個字元對應的Ascll碼值,9+8其實是9對應的Ascll碼和8對應的Ascll碼相加得到新的Ascll碼,結果肯定不是17,因為Ascll碼錶中只有0~9。
為什麼要倒敘轉存進整型陣列?
要留足進位空間。假如是正序存入的(括號內寫陣列下標)
9(0)8(1)9(2)+
9(0)8(1)8(2)9(3)
我們該如何使得這兩個數的個位對齊呢?就算個位對齊成這種樣子
9(1)8(2)9(3)+
9(0)8(1)8(2)9(3)
得到的結果也會因為進位而無法儲存
1(-1)0(0)8(1)7(2)8(3)
陣列下標怎麼可能為-1
如果我們是倒敘轉存進整型陣列的話,一切問題都可以迎刃而解
9(0)8(1)9(2) +
9(0)8(1)8(2)9(3)
8(0)7(1)8(2)0(3)1(4)
不僅個位對齊,由於全部是倒敘,向右進位也可以很好的解決。
首先對字串的處理
void getDigits(int num[],char str[])//把字串儲存在int型別的陣列中 { char digit; int len = strlen(str); for(int i=0; i<len; ++i) { digit=str[i]; num[len-i-1]=digit-'0';//字串倒敘儲存 } }
大數加法
void add(int a[],int b[],int sum[])//同理大數加法
{
for(int i=0; i<MAX; i++)
{
sum[i]=a[i]+b[i];
}
//將十位以上的數字向上進位,將剩餘的數字儲存在自己位置上
for(int i=0; i<MAX; i++)
{
sum[1+i] += sum[i]/10;
sum[i] = sum[i]%10;
}
}
大數乘法
void multiply(int a[],int b[],int sum[])//大數乘法 { /* 陣列a和陣列b逐位相乘,並把結果保存於陣列sum 12345*12345 5與12345中的每位相乘 對於陣列sum sum[i+j]在i=0,j=1,2,3,4,5時儲存的是5和各位相乘的結果 而在i=1,j=1,2,3,4,5時儲存的是4和各位相乘的結果,並累加上次相乘的結果 */ for(int i=0; i<MAX; i++) { for(int j=0; j<MAX; j++) { sum[i+j] += a[i]*b[j]; } } //將十位以上的數字向上進位,將剩餘的數字儲存在自己位置上 for(int i=0; i<MAX*2-1; i++) { sum[1+i] += sum[i]/10; sum[i] = sum[i]%10; } }
大數階層
const int N = 200000;//大數階層所需
int NUM[N];//大數階層所需
void Rank(int n)//大數階層
{
memset(NUM,0,sizeof(NUM));
int s=0,t=0;
NUM[0]=1;
for(int i=2; i<=n; i++)
{
for(int j=0; j<=s; j++)
{
NUM[j]=NUM[j]*i+t;
t=NUM[j]/10000;
NUM[j]=NUM[j]%10000;
}
while(t)
{
NUM[++s]=t%10000;
t=t/10000;
}
}
printf("%d",NUM[s]);
for(int i=s-1; i>=0; i--)
printf("%04d",NUM[i]);
printf("\n");
}
完整的程式碼
#include <cstdio>
#include <iostream>
#include <cstring>
#include <sstream>
#define max(a,b) a>b?a:b
using namespace std;
const int N = 200000;//大數階層所需
const int MAX = 1000;//根據題目要求定義MAX的大小
int NUM[N];//大數階層所需
void getDigits(int num[],char str[])//把字串儲存在int型別的陣列中
{
char digit;
int len = strlen(str);
for(int i=0; i<len; ++i)
{
digit=str[i];
num[len-i-1]=digit-'0';//字串倒敘儲存
}
}
void multiply(int a[],int b[],int sum[])//大數乘法
{
/*
陣列a和陣列b逐位相乘,並把結果保存於陣列sum
12345*12345 5與12345中的每位相乘
對於陣列sum sum[i+j]在i=0,j=1,2,3,4,5時儲存的是5和各位相乘的結果
而在i=1,j=1,2,3,4,5時儲存的是4和各位相乘的結果,並累加上次相乘的結果
*/
for(int i=0; i<MAX; i++)
{
for(int j=0; j<MAX; j++)
{
sum[i+j] += a[i]*b[j];
}
}
//將十位以上的數字向上進位,將剩餘的數字儲存在自己位置上
for(int i=0; i<MAX*2-1; i++)
{
sum[1+i] += sum[i]/10;
sum[i] = sum[i]%10;
}
}
void add(int a[],int b[],int sum[])//同理大數加法
{
for(int i=0; i<MAX; i++)
{
sum[i]=a[i]+b[i];
}
//將十位以上的數字向上進位,將剩餘的數字儲存在自己位置上
for(int i=0; i<MAX; i++)
{
sum[1+i] += sum[i]/10;
sum[i] = sum[i]%10;
}
}
void Rank(int n)//大數階層
{
memset(NUM,0,sizeof(NUM));
NUM[0] = 1;
int p,h; //h表示當前結果的進位,p表示當前的位數
p = 0;
for(int i = 2; i <= n; i++)
{
h = 0;
int j;
for(j = 0; j <= p; j++)
{
NUM[j] = NUM[j] * i + h;
h = NUM[j] / 10;
NUM[j] = NUM[j] % 10;
}
while(h > 0)
{
NUM[j] = h % 10;
h /= 10;
j++;
}
p = j;
}
for(int i = p-2; i >= 0; i--)
{
printf("%d",NUM[i]);
}
printf("\n");
}
int main()
{
char num1[MAX],num2[MAX];
int a[MAX];
int b[MAX];
int sum[MAX*2];
while(scanf("%s%s",&num1,&num2)!=EOF)//多組例項測試
{
if(strcmp(num1,"0")==0||strcmp(num2,"0")==0)
{
printf("0\n");
continue;
}
getchar(); //吞回車 不可少(如果一組例項需要省略)
memset(a,0,sizeof(a)); //初始化陣列a,b
memset(b,0,sizeof(b));
memset(sum,0,sizeof(sum));
getDigits(a,num1);
getDigits(b,num2);
multiply(a,b,sum);//大數加法時可以把函式名字改成add
int j=MAX*2-1;
while(sum[j]==0)
{
j--;
}
for(int i = j; i >= 0; i--)
{
printf("%d",sum[i]);
}
printf("\n");
int num;
cin>>num;
Rank(num);//計算大數階層
}
return 0;
}
需要根據題目要求對模板進行修改。