c語言之大數基本運算
c語言--大數的基本運算
今天我想給大家介紹有關大數運算的方法,大數這裡可以算是一個難點同樣也是重點,以下的程式碼只針對非負數,大家在看之前可以自己思考一下。
大數加法
考慮到整型變數的範圍有限,所以我們用字元陣列來定義輸入的兩個大數,首先要使它們相應的位對齊,位數少的在前補0,然後各個位數的相加要考慮到進位,這裡我定義為s。下面是全部程式碼:
#include"stdio.h"
#include"string.h"
int main()
{
int i,m,len,len1;
char a[100000],b[100000];
scanf("%s",a);
scanf("%s",b);
len=strlen (a);
len1=strlen(b);
m=(len>len1)?len:len1;
for(i=0;i<50;i++)
a[50-1-i]=a[len-1-i];//使其右對齊
for(i=0;i<50-len;i++)
a[i]='0';//前面補0
for(i=0;i<50;i++)
b[50-1-i]=b[len1-1-i];//使其右對齊
for(i=0;i<50-len1;i++)
b[i]='0';//前面補0
for(i=0;i<50;i++)
c[i]='0';//初始化0
s=0;//進位
for(i=0;i<m;i++)
{
c[50 -1-i]=((a[50-1-i]-'0')+(b[50-1-i]-'0')+s)%10+'0';
s=((a[50-1-i]-'0')+(b[50-1-i]-'0')+s)/10;
}
c[50-1-m]=s+'0';
printf("%s",c);
}
這裡需要注意的是:大數用的是字元儲存,不能直接相加,要先將其轉化成數字再進行運算。
emmm,我這裡沒有去掉前導0。
大數階乘
階乘和加法的原理一樣都是相應的位進行運算然後要考慮到進位,這裡我聲明瞭一個自定義函式來計算階乘,切記不要忽略了特殊情況。
#include"stdio.h"
#include"string.h"
void print_factorial( int n)//階乘的函式
{
if(n<0)
{
printf("error\n");
return;
}
else if(n==0)
{
printf("%d\n",1);
return;
}
int a[100000]={1},i,j;
int t=0,len=1,tem;//t為進位,len為位數
for(i=2;i<=n;i++)
{
t=0;
for(j=0;j<len;j++)
{
tem=a[j]*i;//乘積的值
a[j]=(tem+t)%10;//每一位分離出來
t=(tem+t)/10;
if(t!=0&&j==len-1)//判斷位數是否增加
len++;
}
}
for(i=len-1;i>=0;i--)
{
printf("%d",a[i]);//輸出結果
}
}
int main()
{
int n;
scanf("%d",&n);//輸入幾的階乘
print_factorial(n);
}
這裡需要注意的是:a陣列是逆著存最後的結果的,所以輸出時需要逆序輸出。
大數高階冪
這裡我來舉兩個特殊的例子:計算3的100次方和浮點數的冪,其實高階冪的演算法和階乘一樣,只是部分地方需要改動,你只要理解了最核心的程式碼就問題不大。以下是3的100次方的程式碼:
#include"stdio.h"
#include"string.h"
int main()
{
int a[1000]={1},i,j,t,tem,len=1;
char b[1000],c[1000];
gets(b);
for(i=1;i<=100;i++)//計算3^100
{
t=0;
for(j=0;j<len;j++)
{
tem=a[j]*3;
a[j]=(tem+t)%10;//每一位分離出來
t=(tem+t)/10;//t為進位
if(t!=0&&j==len-1)
len++;
}
}//逆著存的
j=0;
for(i=len-1;i>=0;i--)
printf("%d",a[i]);//輸出結果
printf("\n");
}
同樣注意的是,這裡也是逆序輸出哦~
我們再來看一下浮點數的高階冪,它比整數要複雜的多,我們來看一下這種題的要求:
本題中需要注意的點:
1.先找到小數點的位置,紀錄並去掉。
2.去掉無意義的0。
3.紀錄小數點後有效位的位數。
4.每次計算中都要去除無意義的0。
5.計算最後結果中小數點的位置。
6.將小數點加入到計算結果中。
7.去掉最終結果中的無意義的0並輸出。
例如:
輸入:
95.123 12
輸出:548815620517731830194541.899025343415715973535967221869852721
完整程式碼如下:
#include"stdio.h"
#include"string.h"
int len=1;
void multiply(int a[],int n,int num)
{
int i,j,t1,tem;//t1為進位
for(i=1;i<=n;i++)
{
t1=0;
for(j=0;j<len;j++)
{
tem=a[j]*num;
a[j]=(tem+t1)%10;
t1=(tem+t1)/10;
if(t1!=0&&j==len-1)
len++;
}
}//逆著存的
}
int main()
{
char R[10];
int n,num,t,i,j,l;//t為小數點的位數
while(scanf("%s%d",R,&n)!=EOF)
{
int a[150]={1};
num=0,t=0;
for(i=0;i<strlen(R);i++)
{
if(R[i]=='.')
{
t=(strlen(R)-1-i)*n;
}
else
{
num=num*10+R[i]-48;
}
}
multiply(a,n,num);
if(len<=t)//陣列a的位數小於小數位數
{
printf(".");
for(i=0;i<t-len;i++)
printf("0");
for(i=len-1;i>=0;i--)
printf("%d",a[i]);
}
else
{
j=0;
while(a[j]==0&&j<t)//去掉末尾沒用的零
{
j++;
}
l=len;
for(i=len-1;i>=j;i--)//去掉前導0
{
if(a[i]==0)
l--;
if(a[i]!=0)
break;
}
for(i=l-1;i>=j;i--)
{
if(i+1==t)
printf(".");
printf("%d",a[i]);
}
}
printf("\n");
}
}
上面這個題比較複雜,要考慮的問題比較多,所以程式碼寫起來比較繁瑣,希望大家不會的可以好好琢磨一下,試著自己敲出來。
大數乘法
這是我認為這裡面最難的一種運算,它是階乘和加法的結合,首先我們要搞清楚多位數與多位數相乘的原理和過程並從中發現規律。
其核心就是:兩個大數,從末尾開始逐位相乘。相乘結果儲存在另外一個數組裡面(也從陣列末尾開始依次往前儲存)。然後將儲存位置大於9的數進行進位處理。
為了便於理解舉個例子:
我們通過舉例可以發現相乘後的位數k不會超過m+n;這樣我們在寫程式碼時就便利不少。
以下是完整程式碼:
#include<stdio.h>
#include<math.h>
#include<string.h>
#define M 10005
char s1[M],s2[M],s[M];
int a[M],b[M],c[M];
int main()
{
int i,j,m,n,k;
while(~scanf("%s%s",s1,s2))
{
memset(c,0,sizeof(c));
n=strlen(s1);
m=strlen(s2);
k=n+m;//保證相乘後的位數不會大於k
printf("s1的長度=%d s2的長度=%d\n",n,m);
//把字串s1和s2逆序用數字排列
for(i=0; i<n; i++)
a[i]=s1[n-i-1]-'0';
for(i=0; i<m; i++)
b[i]=s2[m-1-i]-'0';
//乘運算
for(i=0; i<n; i++)
for(j=0; j<m; j++)
c[i+j]+=a[i]*b[j];
for(i=0; i<k; i++)
{
if(c[i]>=10)
{
c[i+1]+=c[i]/10;
c[i]%=10;
}
}
//去除前導0
i=k;
while(c[i]==0) i--;
//判斷兩個非負數之積是否為0,以及逆序列印c[]
if(i<0) printf("0");
else
{
for(; i>=0; i--)
printf("%d",c[i]);
}
printf("\n");
}
return 0;
}
先介紹這幾種大數的基本演算法,還有大數減法和大數除法我沒有提,大家可以下去好好想想,掌握了這些你在大數方面的演算法題就沒啥大問題。