-
今天老師講了如何用C語言來做大數與大數的運算
廢話少說,下面是正文
源代碼+註釋
//高精度合集(我把它做成了一個小程序,大家複製下來運行)
#include <stdio.h> //標準輸入輸出頭文件
#include <string.h> //字符串頭文件
#include <math.h> //數學函數
#include <stdlib.h>
char s[10001],ss[10001]; //定義全局變量供下面的程序使用
int a[10001],b[10001],c[10001];
char arr[1000000],cha[1000000];
int d,len;
int Compare(char a[],char b[]) //比較字符串的大小,方法不同於strcmp函數,類似於整型常量的比較
{
int lena,lenb,i;
lena=strlen(a); //a的長度
lenb=strlen(b); //b的長度
if(lena<lenb)
return -1; //如果a的長度比b小,返回-1
else if(lena>lenb)
return 1; //不是,返回1
else
{
if(strcmp(a,b)==0)
return 0;
else
{
for(i=0;i<lena;i++)
{
if(a[i]>b[i])
return 1;
if(a[i]<b[i])
return -1;
}
return 0;
}
}
}
int Judge(char ch[]) //判斷字符串ch是否全爲0,若全爲0,返回1,否則返回0
{
int i,k;
k=strlen(ch);
for(i=0;i<k;i++)
if(ch[i]!='0')
return 0;
return 1;
}
/*-------------高精度加法--------------*/
void jia() //自定義函數"jia"(名字low了一點(好像不是一點,但容易理解不是嗎))
{
int l1 = strlen(s); //"strlen"是一個計算字符串長度的函數
int l2 = strlen(ss); //將輸入的兩個字符串的長度賦值給l1,l2
if (l1 > l2)
len = l1; //將len賦值爲l1,l2中大的那個
else
len = l2;
// for (int i = 0 ; i <= len ; i++) //清零(這裏for循環和下面三句memset都爲將字符串清零 )
// a[i] = b[i] = c[i] = 0;
memset(a,0,sizeof(a)); //清零too(只能清零,不能幹別的)
memset(b,0,sizeof(b)); //這是清零函數(字符串)
//兩個for循環是將輸入的兩個字符串倒過來
for (int i = l1 - 1 ; i >= 0 ; i--) //再將字符串裏的字符轉換爲數字賦值給a,b整型數組
a[l1 - i - 1] = s[i] - '0'; //但爲什麼大數要用字符串存呢?
for (int i = l2 - 1 ; i >= 0 ; i--) //因爲大數太大,用任何整型變量都存不下
b[l2 - i - 1] = ss[i] - '0'; //爲什麼要把字符串倒過來賦值呢?
//因爲大數與大數是一位一位運算的,還要涉及進位等
for (int i = 0 ; i < len ; i++)
{
a[i] = a[i] + b[i]; //運算
a[i+1]+= a[i] / 10; //如有進位,在後一位上加上
a[i] = a[i] % 10; //原來那一位減掉進位了的
}
if (a[len] != 0)
len++; //如果有進位就多顯示一位(這句話很重要)
printf("結果:\n");
printf("%s + %s = ",s,ss);
for (int i = len - 1 ;i >= 0 ;i--) //輸出結果
printf("%d",a[i]);
printf("\n");
} //高精度加法你懂了嗎?
/*-------------高精度減法--------------*/
void jian()
{
int l1 = strlen(s); //字符串長度
int l2 = strlen(ss);
int flag = 0; //一個記錄正負的變量(後面就知道啦)
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
if ( l1 < l2 || (strcmp(s,ss) < 0 && l1 == l2) ) //這個比較重要是來判斷前後兩數的大小的
{ //不然一個小的數減一個大的數是大於零的就尷尬了
flag = 1; //這裏是把正負記錄下來
for (int i = l2 - 1 ; i >= 0 ; i--) //倒過來輸入
a[l2 - i - 1] = ss[i] - '0'; //將字符串裏的字符轉換爲數字
for (int i = l1 - 1 ; i >= 0 ; i--)
b[l1 - i - 1] = s[i] - '0';
}
else
{
for (int i = l1 - 1 ; i >= 0 ; i--) //同理,倒過來輸入
a[l1 - i - 1] = s[i] - '0';
for (int i = l2 - 1 ; i >= 0 ; i--)
b[l2 - i - 1] = ss[i] - '0';
}
if (l1 > l2)
len = l1; //len賦值爲其中大的數
else
len = l2;
for (int i = 0 ; i < len ; i++)
{
a[i] = a[i] - b[i]; //運算
if (a[i] < 0) //如果減得多了
{
a[i+1]-=1; //向前要一位
a[i]+=10;
}
}
while (a[len - 1] == 0 && len>1)
len--; //while去零法,瞭解一下(名字現編的,別搜百度了)
printf("結果:\n");
printf("%s - %s = ",s,ss);
if (flag == 1)
printf("-"); //如果結果是負的,先輸出一個負號
for (int i = len - 1 ;i >= 0 ;i--) //再輸出結果
printf("%d",a[i]);
printf("\n"); //換行
} //高精度減法你懂了嗎?
/*-------------高精度乘法(低)--------------*/
void cheng_di() //這裏的低是指高精度乘低精度,OK?
{
len = strlen(s); //記錄字符長長度(這裏只有一個字符串)
memset(a,0,sizeof(a)); //清空數組
for (int i = 0 ; i < len ; i++) //將字符串裏的字符轉換爲數字
a[len - i - 1] = s[i] - '0';
int jinwei = 0;
for (int i = 0 ; i < len ; i++)
{
a[i] = a[i] * d + jinwei; //運算
jinwei = a[i] / 10; //進位
a[i] %= 10;
}
if (jinwei != 0)
{
a[len] = jinwei; //將進位後的數字保存在最後一位
len++; //並把位數+1
while (a[len - 1] >= 10)
{
a[len] = a[len - 1] / 10; //把進位搞好後再把後面的數字也弄好
a[len - 1] %= 10;
len++; //把位數++
}
}
while (a[len - 1] == 0 && len > 1)
len--; //while去零法
printf("結果:\n");
printf("%s × %d = ",s,d);
for (int i = len - 1 ; i >= 0; i--) //輸出結果
printf("%d",a[i]);
printf("\n"); //換行
} //高精度乘法(低)你懂了嗎
/*-------------高精度乘法(高)--------------*/
void cheng_gao() //高是指高精度乘高精度
{
len = strlen(s);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
for (int i = 0 ; i < len ; i++)
a[len - i - 1] = s[i] - '0'; //轉化
int lenn = strlen(ss);
for (int i = 0 ; i < lenn ; i++)
b[lenn - i - 1] = ss[i] - '0';
memset(c,0,sizeof(c)); //清零
for (int i = 0 ; i < len ; i++)
for (int j = 0 ; j < lenn ; j++)
c[i + j] += a[i] * b[j]; //運算(這個就有一點複雜了)
int l = len + lenn - 1; //l是結果的最高位數
for (int i = 0 ; i < l ;i++)
{
c[i + 1] += c[i] / 10; //保證每一位的數都只有一位,並進位
c[i] %= 10;
}
if (c[l] > 0) l++; //保證最高位數是對的
while (c[l - 1] >= 10)
{
c[l] = c[l - 1] / 10;
c[l - 1] %= 10;
l++;
}
while (c[l - 1] == 0 && l > 1)
l--; //while去零法
printf("結果:\n");
printf("%s × %s = ",s,ss);
for (int i = l - 1; i >= 0 ; i--) //輸出結果
printf("%d",c[i]);
printf("\n"); //換行
} //高精度乘法(高)你懂了嗎
/*-------------高精度除法(低)--------------*/
void chu_di() //高精除低精
{
int yu=0;
memset(a,0,sizeof(a)); //清空數組a
memset(b,0,sizeof(b)); //清空數組b
len=strlen(s); //s的長度
for(int i=0;i<=len-1;i++) //將
a[i+1]=s[i]-'0';
for(int ii=1;ii<=len;ii++)
{
b[ii]=(yu*10+a[ii])/d;
yu=(yu*10+a[ii])%d;
}
int lenb=1;
while(b[lenb]==0&&lenb<len)
lenb++;
printf("結果:\n");
printf("%s ÷ %d = ",s,d);
for(int j=lenb;j<=len;j++)
printf("%d",b[j]);
if(yu!=0)
printf("......%d",yu);
printf("\n");
}
/*-------------高精度除法(高)--------------*/
void Sub(char a1[],char b1[])
{//a1爲被減數,b1爲減數
int lena,lenb,i,j,k,flag;
int a[1000]={0},b[1000]={0},d[1000]={0};
lena=strlen(a1);
lenb=strlen(b1);
if(Compare(a1,b1)>=0)
{//若被減數大於等於減數
for(i=0;i<lena;i++) a[i]=a1[lena-1-i]-'0';
for(i=0;i<lenb;i++) b[i]=b1[lenb-1-i]-'0';
flag=0;//結果正的標誌
}
else
{//若被減數小於減數
for(i=0;i<lenb;i++) a[i]=b1[lenb-1-i]-'0';
for(i=0;i<lena;i++) b[i]=a1[lena-1-i]-'0';
flag=1;//結果負的標誌
}
k=lena>lenb?lena:lenb;
for(i=0;i<k;i++)
{//大數減小數
if(a[i]<b[i])
{//若被減數不夠減,向高位借一位
a[i+1]--;
d[i]=a[i]-b[i]+10;
}
else d[i]=a[i]-b[i];
}
//若較高位已爲,並且不止位時
while(!d[i-1])
{ k--; i--; }
//根據flag,輸出有無"-"
if(!flag)
{
for(i=0;i<k;i++)
{//將結果轉化爲字符逆着賦給數組c
if(!i&&!d[k-i-1])//若差的第一個字母爲0,則馬上跳過
continue;
cha[i]=d[k-i-1]+'0';
}
}
else
{
cha[0]='-';
for(i=1;i<=k;i++)
{//將結果轉化爲字符逆着賦給數組c
if(i==1&&!d[k-i])//若差的第一個字母爲,則馬上跳過
continue;
cha[i]=d[k-i]+'0';//注意d的下標,不是k-i-1
}
}
if(Judge(cha))//若差全爲,則只輸出一個
strcpy(cha,"0");
}
void chu_gao()
{
char a[1000],b[1000],t[1000];
int lens,lent,i,j,k,flag=0;
memset(arr,0,sizeof(arr));
if(Compare(s,ss)<0) //若被除數小於除數,則商爲0,餘數爲被除數
strcpy(arr,s);
else if(!Compare(s,ss)) //若兩數相等,則商爲1,餘數爲0
cha[0]='1';
else //若被除數大於除數
{
j=lent=0; lens=strlen(s);
memset(b,0,sizeof(b));
memset(t,0,sizeof(t));
for(i=0;i<lens;i++) //計算得到被除數的前幾位,得到整型數組形式的商
//t的一個元素表示一次相除的商
{
b[j++]=s[i];
flag=0;
while(Compare(b,ss)>=0)
{
Sub(b,ss);
strcpy(b,cha);
memset(cha,0,sizeof(cha));
t[lent]++;
flag=1; //控制t的元素的位置
}
if(flag) //將商轉換爲字符
t[lent]+='0';
else //當被除數前幾位小於除數,商補
t[lent]='0';
if(!strcmp(b,"0")) //若b爲''
j=0;
else //繼續在b的後面加值
j=strlen(b);
lent++;
}
k=0;
for(i=0;i<lent;i++)
if(t[i]!='0')
break; //找到t數組中第一個不爲0的位置
for(j=i;j<lent;j++)
cha[k++]=t[j];
strcpy(arr,b);
}
if(Judge(cha))
strcpy(cha,"0");
if(Judge(arr))
strcpy(arr,"0");
}
/*-------------高精度階乘--------------*/ //這個函數不是我寫的,特此申明,侵刪
unsigned int *x; //動態數組
/* 求N!的位數公式 log10(1)+log10(2)+···+log10(n) 取整加1 */
int wei(int d)
{
int i;
double sum=0;
for(i=1;i<=d;i++) sum+=log10((double)i);
/* 以萬爲進制,一位可以表示4個數,減少存儲空間 */
return (int)((sum+1)/4+1);
}
void jiecheng()
{
int i,j,jinwei,weishu=1,temp;
/* 依據階乘位數申請動態數組 */
x=(unsigned int*) malloc(wei(d)*sizeof(int));
x[0]=1;
if(d>30000)
printf("\n這數字太大了!\n可能有點慢,稍等!\n");
else
if(d>2000)
printf("\n這數字有點大呀!\n\n");
for(i=2;i<=d;i++)
{
jinwei=0;
for(j=1;j<=weishu;j++)
{
temp=x[j-1]*i+jinwei;
if (temp>=1)
{
/* 以萬爲進制,提高運算速度 */
x[j-1]=temp%10000;
jinwei=temp/10000;
}
}
while(jinwei)
{
weishu++;
x[weishu-1]=jinwei%10000;
jinwei/=10000;
}
}
printf("結果:\n");
/* 先輸出第一個數,防止首位出現0 */
printf("%d ! = ",d);
printf("%d",x[weishu-1]);
/* 輸出其餘的數,因爲萬進制,需要補0 */
for(j=weishu-2;j>=0;j--) printf("%04d",x[j]);
/* 釋放申請的內存 */
free(x);
}
void print()
{
printf("...............高精度模板(By STY)...............\n");
printf("高精度加法請打“1”\n");
printf("高精度減法請打“2”\n");
printf("高精度乘法(低)請打“3”\n");
printf("高精度乘法(高)請打“4”\n");
printf("高精度除法(低)請打“5”\n");
printf("高精度除法(高)請打“6”\n");
printf("高精度階乘請打“7”\n");
printf("退出請按“Ctrl+Z”(在鍵盤上),並按回車,謝謝使用!\n");
printf("請輸入:(1~7)\n");
}
void print_jia()
{
printf("\n您選擇了:高精度加法\n");
printf("請輸入兩個數字:\n");
printf("數字:\n");
scanf("%s%s",s,ss);
jia(); //引用高精度加法函數
}
void print_jian()
{
printf("\n您選擇了:高精度減法\n");
printf("請輸入兩個數字:\n");
printf("數字:\n");
scanf("%s%s",s,ss);
jian(); //引用高精度減法函數
}
void print_cheng_di()
{
printf("\n您選擇了:高精度乘法(低)\n");
printf("請輸入兩個數字:\n");
printf("數字:\n");
scanf("%s%d",s,&d);
cheng_di(); //引用高精度乘法(低)函數
}
void print_cheng_gao()
{
printf("\n您選擇了:高精度乘法(高)\n");
printf("請輸入兩個數字:\n");
printf("數字:\n");
scanf("%s%s",s,ss);
cheng_gao(); //引用高精度乘法(高)函數
}
void print_chu_di()
{
printf("\n您選擇了:高精度除法(低)\n");
printf("請輸入兩個數字:\n");
printf("數字:\n");
scanf("%s%d",s,&d);
chu_di(); //引用高精度除法(低)函數
}
void print_chu_gao()
{
printf("\n您選擇了:高精度除法(高)\n");
printf("請輸入兩個數字:\n");
printf("數字:\n");
scanf("%s%s",s,ss);
if(Judge(ss))
printf("0不能作除數。\n\n");
else
{
chu_gao(); //引用高精度除法(高)函數
if(!Judge(arr))
printf("%s / %s=%s......%s\n\n",s,ss,cha,arr);
else
printf("%s / %s=%s\n\n",s,ss,cha); //如果沒有餘數就不輸出
}
}
void print_jiecheng()
{
printf("\n您選擇了:高精度階乘\n");
printf("請輸入一個數字:\n");
printf("這個數字最好別超過120000,不然太慢,等不起(可能要算幾十分鐘)\n");
printf("數字:\n");
scanf("%d",&d);
jiecheng(); //引用高精度階乘函數
}
/*-------------主程序--------------*/
int main()
{
int choice,i;
//原來將print中的代碼上面寫一遍,下面複製一遍,後寫成了函數
print();
while(scanf("%d",&choice)!=EOF) //這個程序可循環
{
// if(choice==1)
// print_jia();
// else if(choice==2)
// print_jian();
// else if(choice==3)
// print_cheng_di();
// else if(choice==4)
// print_cheng_gao();
// else if(choice==5)
// print_chu_di();
// else if(choice==6)
// print_chu_gao();
// else if(choice==7)
// print_jiecheng();
// else
// printf("沒有這一項!別開玩笑了!\n");
//上面註釋的那一段和下面用switch-case的代碼是一個意思
switch(choice)
{
case 1:print_jia();break;
case 2:print_jian();break;
case 3:print_cheng_di();break;
case 4:print_cheng_gao();break;
case 5:print_chu_di();break;
case 6:print_chu_gao();break;
case 7:print_jiecheng();break;
default:printf("沒有這一項!別開玩笑了!\n");break;
}
printf("\n\n"); //空行
print();
}
return 0;
}
希望大家喜歡這篇文章!!!
如有問題請留言,謝謝!!!