大數四則運算的簡單演算法
大數相加
題目:任意兩個數相加,計算結果
還有種特殊情況 這個題目中的兩個數可能為正,可能為負
第一種情況,為正
思路:
1.將字串倒序並轉化為數字
2.逐位相加,並存入陣列s[i]
3.對陣列進行進位制換算(這裡有個需要特別注意的是 換算到最後,要考慮最後一位進位制k值是否為零)
4.將陣列反序輸出
所用程式碼如下
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> using namespace std; #define Max 100000 int main() { char str1[Max+10],str2[Max+10]; while( cin>>str1>>str2) { int a[Max+10]={0},b[Max+10]={0},s[Max*2+10]={0},len1,len2,len; len1=strlen(str1); len2=strlen(str2); len=len1>len2?len1:len2; int x=0; //將字串倒序並轉化為數字 for(int i=len1-1;i>=0;i--) a[x++]=str1[i]-'0'; x=0; for(int i=len2-1;i>=0;i--) b[x++]=str2[i]-'0'; int k=0; //逐位相加,並存入陣列s[i] // 對陣列進行進位制換算 for(int i=0;i<len;i++) { s[i]=(a[i]+b[i]+k)%10; k=(a[i]+b[i]+k)/10; } if(k!=0) printf("%d",k); int i; //將陣列反序輸出 for(i=len-1;i>=0;i--) { if(s[i]!=0) break; } for(;i>=0;i--) { printf("%d",s[i]); } printf("\n"); } return 0; }
第二種情況 可能為負
思路
1.同上,先倒序輸出,並轉化為數字
2.判斷該數是否為負數,若為負,則對陣列內的每一個數字賦一個負號
3.逐位相加
4.判斷陣列s[i]的最後一位是否為負,分情況討論,若為負,則輸出一個負號
5.倒序輸出,並且對s[i]加絕對值
所需程式碼如下:
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; char aa[10010],bb[10010]; int a[10010],b[10010],c[10010]; int lena,lenb,len; int main() { while(~scanf("%s%s",aa,bb)) { memset(a,0,sizeof(a)); memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); int x=0; lena=strlen(aa),lenb=strlen(bb); //反序輸出 for(int i=lena-1; i>0; i--) a[x++]=aa[i]-'0'; //判斷是否為負 if(aa[0]=='-') { lena--; for(int i=0; i<lena; i++) a[i]=-a[i]; } else a[lena-1]=aa[0]-'0'; x=0; for(int i=lenb-1; i>0; i--) b[x++]=bb[i]-'0'; if(bb[0]=='-') { lenb--; for(int i=0; i<lenb; i++) b[i]=-b[i]; } else b[lenb-1]=bb[0]-'0'; int k=0; len=lena>lenb?lena:lenb; //逐位相加 for(int i=0; i<len; i++) { c[i]=(a[i]+b[i]+k)%10; k=(a[i]+b[i]+k)/10; } if(k) c[len++]=k; while(len>1&&c[len-1]==0) len--; int flag=1; //判斷是否為負數 if(c[len-1]>=0) { for(int i=0; i<len; i++) { while(c[i]<0) { c[i+1]--; c[i]+=10; } } } if(c[len-1]<0) { flag=0; for(int i=0; i<len; i++) { while(c[i]>0) { c[i+1]++; c[i]-=10; } } } if(!flag) printf("-"); //倒序輸出,並且加上絕對值 while(len>1&&c[len-1]==0) len--; for(int i=len-1; i>=0; i--) printf("%d",abs(c[i])); printf("\n"); } }
大數相乘
題目: 任意兩個數相乘,計算其結果
題目分析:該題主要注意結果的範圍,簡單的數字相乘,一般的程式碼程式可以運算,但大數的運算可能就會出現結果為負數,或者結果比所成積要小。所以要使用字串的形式來進行運算,儲存結果。
思路:
1.先將字串倒序並轉換為數字
2.逐位相乘,並存入一個數組s[i+j]中
3.處理進位,並消去多餘的0
4.轉換並把陣列s[i]反轉輸出
所用程式碼如下:
#include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<iostream> using namespace std; #define Max 10000 int main() { char str1[Max],str2[Max]; int len1,len2; while(cin>>str1>>str2) { int a[Max+10]={0},b[Max+10]={0},s[2*Max+10]={0}; len1=strlen(str1); len2=strlen(str2); int x=0; //將字串反轉過來,轉化為數字 for(int i=len1-1;i>=0;i--) { a[x]=str1[i]-'0'; x++; } x=0; for(int i=len2-1;i>=0;i--) { b[x]=str2[i]-'0'; x++; } //對兩組字串中的數逐位相乘,存於s[i+j] for(int i=0;i<len1;i++) { for(int j=0;j<len2;j++) { s[i+j]+=(a[i]*b[j]); } } //得到的結果進行進位制處理 for(int j=0;j<Max*2;j++) { if(s[j]>=10) { s[j+1]+=s[j]/10; s[j]%=10; } } int i; //除去多餘的0 for(i=Max*2-1;i>=0;i--) { if(s[i]!=0) break; } //反轉陣列並輸出結果 for(;i>=0;i--) { printf("%d",s[i]); } printf("\n"); } return 0; }
這是小編第一次編寫部落格,因為小編是剛學沒多久,裡面的程式碼也是比較淺顯易懂的,以後小編我會努力提升自我的水平的。。。。
大數減法
題目:任意兩個數相減,求其結果
思路:
1.
2.
3.
4.
#include<stdio.h>
#include<string.h>
#define MAX 1000//大數的最大位數
int main()
{
int sum[MAX]= {0}; //存放計算的結果,低位在前,高位在後,即sum[0]是低位
char a[]="987654321987654321";//第一個大數
char b[]="123456789123456789";//第二個大數
int i,j,len,blag;
char *temp_a=a,*temp_b=b,*temp;
int n2[MAX]= {0};
int a1=strlen(a);//計算陣列num1的長度,即大數的位數
int a2=strlen(b);//計算陣列num2的長度,即大數的位數
//在進行減法之前要進行一些預處理
blag=0;//為0表示結果是正整數,為1表示結果是負整數
if(a1<a2)//如果被減數位數小於減數
{
blag=1;//標記結果為負數
//交換兩個數,便於計算
temp=temp_a;
temp_a=temp_b;
temp_b=temp;
len=a1;
a1=a2;
a2=len;
}
else if(a1==a2)//如果被減數的位數等於減數的位數
{
//判斷哪個數大
for(i=0; i<a1; i++)
{
if(a[i]==b[i])
continue;
if(a[i]>b[i])
{
blag=0;//標記結果為正數
break;
}
else
{
blag=1;//標記結果為負數
//交換兩個數,便於計算
temp=temp_a;
temp_a=temp_b;
temp_b=temp;
break;
}
}
}
len=a1>a2?a1:a2;//獲取較大的位數
//將num1字元陣列的數字轉換為整型數且逆向儲存在整型陣列sum中,即低位在前,高位在後
for(i=a1-1,j=0; i>=0; i--,j++)
sum[j]=a[i]-48;
//轉換第二個數
for(i=a2-1,j=0; i>=0; i--,j++)
n2[j]=b[i]-48;
//將兩個大數相減
for(i=0; i<=len; i++)
{
sum[i]=sum[i]-n2[i];//兩個數從低位開始相減
if(sum[i]<0)//判斷是否有借位
{
//借位
sum[i]+=10;
sum[i+1]--;
}
}
//計算結果長度
for(i=a1-1; i>=0&&sum[i]==0; i--)
len=i+1;
if(blag==1)
{
sum[len]=-1;//在高位新增一個-1表示負數
len++;
}
//輸出結果
printf("%s\n-\n%s\n=\n",a,b);
if(sum[i=len-1]<0)//根據高位是否是-1判斷是否是負數
{
printf("-");//輸出負號
i--;
}
for(; i>=0; i--)
printf("%d",sum[i]);
printf("\n");
return 0;
}
大數相除
大數除法是四則運算裡面最難的一種。不同於一般的模擬,除法操作不是模仿手工除法,而是利用減法操作來實現的。其基本思想是反覆做除法,看從被除數裡面最多能減去多少個除數,商就是多少。逐個減顯然太慢,要判斷一次最多能減少多少個整數(除數)的10的n次方。
以7546除以23為例:
先用7546減去23的100倍,即減去2300,可以減3次,餘下646,此時商就是300 (300=100*3);
然後646減去23的10倍,即減去230,可以減2次,餘下186,此時商就是320 (320=300+10*2);
然後186減去23,可以減8次,餘下2,此時商就是328 (328=320+1*8);
因為2除以23的結果小於1,而我們又不用計算小數點位,所以不必再繼續算下去了。
下面是C語言的兩個正大數相除的參考程式碼,計算結果中沒有小數:
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
#define MAX 1000
/*
12 函式SubStract功能:
13 用長度為len1的大整數p1減去長度為len2的大整數p2
14 結果存在p1中,返回值代表結果的長度
15 不夠減:返回-1 , 正好夠:返回0
16 */
int SubStract(int *p1, int len1, int *p2, int len2)
{
int i;
if(len1 < len2)
return -1;
if(len1 == len2 )
{
// 判斷p1 > p2
for(i = len1-1; i >= 0; i--)
{
if(p1[i] > p2[i]) // 若大,則滿足條件,可做減法
break;
else if(p1[i] < p2[i]) // 否則返回-1
return -1;
}
}
for(i = 0; i <= len1-1; i++) // 從低位開始做減法
{
p1[i] -= p2[i]; // 相減
if(p1[i] < 0) // 若是否需要借位
{
// 借位
p1[i] += 10;
p1[i+1]--;
}
}
for(i = len1-1; i >= 0; i--) // 查詢結果的最高位
{
if( p1[i] ) //最高位第一個不為0
return (i+1); //得到位數並返回
}
return 0; //兩數相等的時候返回0
}
/*
51 大數除法---結果不包括小數點
52 num1 被除數
53 num2 除數
54 sum 商,存放計算的結果,即:num1/num2=sum
55 返回陣列sum的有效長度,即商的位數
56 */
int Division(char num1[], char num2[], char sum[])
{
int k, i, j;
int len1, len2, len=0; //大數位數
int dValue; //兩大數相差位數
int nTemp; //Subtract函式返回值
int num_a[MAX] = {0}; //被除數
int num_b[MAX] = {0}; //除數
int num_c[MAX] = {0}; //商
len1 = strlen(num1); //獲得大數的位數
len2 = strlen(num2);
//將數字字元轉換成整型數,且翻轉儲存在整型陣列中
for( j = 0, i = len1-1; i >= 0; j++, i-- )
num_a[j] = num1[i] - '0';
for( j = 0, i = len2-1; i >= 0; j++, i-- )
num_b[j] = num2[i] - '0';
if( len1 < len2 ) //如果被除數小於除數,直接返回-1,表示結果為0
{
return -1;
}
dValue = len1 - len2; //相差位數
for (i = len1-1; i >= 0; i--) //將除數擴大,使得除數和被除數位數相等
{
if (i >= dValue)
num_b[i] = num_b[i-dValue];
else //低位置0
num_b[i] = 0;
}
len2 = len1;
for(j = 0; j <= dValue; j++ ) //重複呼叫,同時記錄減成功的次數,即為商
{
while((nTemp = SubStract(num_a, len1, num_b+j, len2-j)) >= 0)
{
len1 = nTemp; //結果長度
num_c[dValue-j]++; //每成功減一次,將商的相應位加1
}
}
// 計算商的位數,並將商放在sum字元陣列中
for(i = MAX-1; num_c[i] == 0 && i >= 0; i-- ); //跳過高位0,獲取商的位數
if(i >= 0)
len = i + 1; // 儲存位數
for(j = 0; i >= 0; i--, j++) // 將結果複製到sum陣列中
sum[j] = num_c[i] + '0';
sum[j] = '\0'; // sum字元陣列結尾置0
return len; // 返回商的位數
}
int main()
{
int i;
int len; // 商的位數
char num1[MAX] = "1234567899876543210"; // 第一個大數
char num2[MAX] = "20160415123025"; // 第二個大數
char sum[MAX] = {0}; // 計算結果
//scanf("%s", num1); //以字串形式讀入大數
//scanf("%s", num2);
len = Division(num1, num2, sum);
//輸出結果
printf("%s\n ÷\n%s\n =\n", num1, num2);
if( len>=0 )
{
for(i = 0; i < len; i++ )
printf("%c", sum[i]);
}
else
{
printf("0");
}
printf("\n");
return 0;
}