1. 程式人生 > >C++實現高精度大整數(大數)的四則運算

C++實現高精度大整數(大數)的四則運算

為了便於大整數的運算,我們首先定義一個結構體,用於儲存大整數。

struct bign{
	int d[1000];
	int len;
	//下面定義建構函式,用來初始化! 
	bign(){
		memset(d,0,sizeof(d));
		len=0;
	}
}; 

其中,bign(){}函式沒有任何返回值,作為bign結構體的解構函式,用於對定義的bign進行初始化。

一般來說,大整數一般是使用字串輸入的,下面將字串儲存的大整數存放在結構體中:

bign change(char str[]){
	bign a;
	a.len=strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i]=str[a.len-i-1]-'0';//這裡把大整數的地位切換為高位 
	}
	return a; 
} 

返回的是bign型別的,也就是將char型別轉換為了我剛才定義的大整數型別。

對於演算法競賽初級來說,比較兩個大整數的大小的題目也是非常常見的,下面為比較大小函式。

int compare(bign a,bign b){
	if(a.len>b.len)return 1;//a大於b
	else if(a.len<b.len)return -1;//a<b
	else{
		for(int i=a.len-1;i>=0;i++){
			if(a.d[i]>b.d[i])return 1;
			else if(a.d[i]<b.d[i])return -1;
		}
		return 0;//兩個數相等 
	} 
} 

下面是加法法則,其演算法與小學時的加法運算相同!!!和小學的演算法相同。。。
bign add(bign a,bign b){
	bign c;
	int carry=0;//這裡的carry表示進位
	for(int i=0;i<a.len||i<b.len;i++){
		int temp=a.d[i]+b.d[i]+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	} 
	if(carry!=0){//如果最後一位的進位不為0,直接付給結果的最高位
	   c.d[c.len++] =carry;
	}
	return c;
} 

//值得注意的是,上面的演算法的條件都是非負整數,那麼如果有一個數是負數怎麼辦呢????

//如果有一個數字為負數,我們可以使用高精度減法

下面介紹高精度減法

bign sub(bign a,bign b){
	bign c;
	for(int i=0;i<a.len||i<b.len;i++){
		if(a.d[i]<b.d[i]) {//如果不夠減法,則向高位借位 
			if(a.d[i+1]>0){
			
			a.d[i+1]--;
			a.d[i]+=10; 
		}
		}
		c.d[c.len++]=a.d[i]-b.d[i];
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}//去除高位為0的!同時保留一個最低位 
	return c;
} 

高精度與低精度乘法運算規則
bign multi(bign a,int b){
	bign c;
	int carry=0;
	for(int i=0;i<a.len;i++){
		int temp=a.d[i]*b+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	}
	while(carry!=0)
	{
		c.d[c.len++]=carry%10;
		carry/=10;
	}
	return c;
} 


高精度與低精度的除法

bign divide(bign a,int b,int &r){//r為餘數,這裡表示為引用
    bign c;
	c.len=a.len;
	for(int i=a.len-1;i>=0;i--){
		r=r*10+a.d[i];
		if(r<b) c.d[i]=0;
		else{
			c.d[i]=r/b;
			r=r%b;
		}
	} 
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}
	return c;
} 

列印結果!
void print(bign a){
	for(int i=a.len-1;i>=0;i--)
	{
		printf("%d",a.d[i]);
	}
}

主函式,這裡只調用兩個數 相加的情況
int main(){
	char str1[1000],str2[1000];
	scanf("%s%s",str1,str2);
	bign a=change(str1);
	bign b=change(str2);
	print(add(a,b)); 
	return 0;
}

完整程式碼:
#include <stdio.h>
#include<iostream>
#include <string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
//基於C++的大整數運算
//首先,為了方便後面運算,我們先定義一個結構體
struct bign{
	int d[1000];
	int len;
	//下面定義建構函式,用來初始化! 
	bign(){
		memset(d,0,sizeof(d));
		len=0;
	}
}; 
//一般來說,大整數一般是使用字串輸入的,下面將字串儲存的大整數
//存放在結構體中
bign change(char str[]){
	bign a;
	a.len=strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i]=str[a.len-i-1]-'0';//這裡把大整數的地位切換為高位 
	}
	return a; 
} 
//比較兩個大整數的大小
int compare(bign a,bign b){
	if(a.len>b.len)return 1;//a大於b
	else if(a.len<b.len)return -1;//a<b
	else{
		for(int i=a.len-1;i>=0;i++){
			if(a.d[i]>b.d[i])return 1;
			else if(a.d[i]<b.d[i])return -1;
		}
		return 0;//兩個數相等 
	} 
} 
//下面是大數的四則運演算法則
bign add(bign a,bign b){
	bign c;
	int carry=0;//這裡的carry表示進位
	for(int i=0;i<a.len||i<b.len;i++){
		int temp=a.d[i]+b.d[i]+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	} 
	if(carry!=0){//如果最後一位的進位不為0,直接付給結果的最高位
	   c.d[c.len++] =carry;
	}
	return c;
} 
//值得注意的是,上面的演算法的條件都是非負整數,那麼如果有一個數是負數怎麼辦呢????
//如果有一個數字為負數,我們可以使用高精度減法
bign sub(bign a,bign b){
	bign c;
	for(int i=0;i<a.len||i<b.len;i++){
		if(a.d[i]<b.d[i]) {//如果不夠減法,則向高位借位 
			if(a.d[i+1]>0){
			
			a.d[i+1]--;
			a.d[i]+=10; 
		}
		}
		c.d[c.len++]=a.d[i]-b.d[i];
	}
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}//去除高位為0的!同時保留一個最低位 
	return c;
} 
//高精度的乘法運算規則
bign multi(bign a,int b){
	bign c;
	int carry=0;
	for(int i=0;i<a.len;i++){
		int temp=a.d[i]*b+carry;
		c.d[c.len++]=temp%10;
		carry=temp/10;
	}
	while(carry!=0)
	{
		c.d[c.len++]=carry%10;
		carry/=10;
	}
	return c;
} 
//高精度與低精度的除法
bign divide(bign a,int b,int &r){//r為餘數,這裡表示為引用
    bign c;
	c.len=a.len;
	for(int i=a.len-1;i>=0;i--){
		r=r*10+a.d[i];
		if(r<b) c.d[i]=0;
		else{
			c.d[i]=r/b;
			r=r%b;
		}
	} 
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}
	return c;
} 
void print(bign a){
	for(int i=a.len-1;i>=0;i--)
	{
		printf("%d",a.d[i]);
	}
}
int main(){
	char str1[1000],str2[1000];
	scanf("%s%s",str1,str2);
	bign a=change(str1);
	bign b=change(str2);
	print(add(a,b)); 
	return 0;
}


以上內容的參考資料:《演算法筆記》——第五章入門篇(3)——數學問題

相關練習題:

PAT:https://www.patest.cn/contests/pat-b-practise/1017    

時間限制 100 ms
記憶體限制 65536 kB
程式碼長度限制 8000 B
判題程式 Standard 作者 CHEN, Yue

本題要求計算A/B,其中A是不超過1000位的正整數,B是1位正整數。你需要輸出商數Q和餘數R,使得A = B * Q + R成立。

輸入格式:

輸入在1行中依次給出A和B,中間以1空格分隔。

輸出格式:

在1行中依次輸出Q和R,中間以1空格分隔。

輸入樣例:
123456789050987654321 7
輸出樣例:
17636684150141093474 3
直接使用上面的演算法

AC程式碼:

#include <stdio.h>
#include<iostream>
#include <string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
//基於C++的大整數運算
//首先,為了方便後面運算,我們先定義一個結構體
struct bign{
	int d[1000];
	int len;
	//下面定義建構函式,用來初始化! 
	bign(){
		memset(d,0,sizeof(d));
		len=0;
	}
}; 
//一般來說,大整數一般是使用字串輸入的,下面將字串儲存的大整數
//存放在結構體中
bign change(char str[]){
	bign a;
	a.len=strlen(str);
	for(int i=0;i<a.len;i++){
		a.d[i]=str[a.len-i-1]-'0';//這裡把大整數的地位切換為高位 
	}
	return a; 
} 
//高精度與低精度的除法
bign divide(bign a,int b,int &r){//r為餘數,這裡表示為引用
    bign c;
	c.len=a.len;
	for(int i=a.len-1;i>=0;i--){
		r=r*10+a.d[i];
		if(r<b) c.d[i]=0;
		else{
			c.d[i]=r/b;
			r=r%b;
		}
	} 
	while(c.len-1>=1&&c.d[c.len-1]==0){
		c.len--;
	}
	return c;
} 
void print(bign a){
	for(int i=a.len-1;i>=0;i--)
	{
		printf("%d",a.d[i]);
	}
}
int main(){
	char str1[1000];
	int b;
	scanf("%s%d",str1,&b);
	bign a=change(str1);
	int r=0;
	print(divide(a,b,r));
    printf(" %d",r); 
	return 0;
}


以上內容原創,轉載請註明出處!