C++ 기본 알고리즘 ①——고정밀 덧셈과 뺄셈 계산

1. 소개

컴퓨터를 사용하여 수치 계산을 수행할 때 때때로 다음과 같은 문제에 직면합니다. n! 의 정확한 결과는 무엇입니까?
n이 30보다 작을 때는 물론 컴퓨터에 딸린 계산기를 이용해 계산할 수 있습니다. 하지만 100!을 만나면 정확한 결과를 직접 계산할 수 있는 방법이 없습니다. 또 다른 예로, 두 개의 20,000자리 숫자의 합을 구합니다.

그렇다면 정밀도 누락 문제를 해결하는 방법은 무엇입니까?
고정확도 알고리즘은 큰 숫자를 처리하기 위한 수학적 계산 방법입니다.

  • 일반적인 과학적인 계산에서는 소수점 이하 몇 백 자리 이상까지 계산이 이루어지는 경우가 많으며, 물론 수천억에서 수백억에 이르는 큰 숫자일 수도 있습니다. 일반적으로 우리는 이러한 유형의 숫자를 고정밀 숫자라고 부릅니다. 고정밀 알고리즘은 컴퓨터를 사용하여 매우 큰 데이터에 대한 덧셈, 뺄셈, 곱셈, 나눗셈, 지수화, 계승, 제곱근 및 기타 연산을 시뮬레이션합니다. 매우 큰 숫자는 컴퓨터에 정상적으로 저장할 수 없습니다.
  • 그래서 이 숫자를 한 자리 또는 네 자리로 나누어 배열로 저장하고, 배열을 이용하여 숫자를 표현하므로 이 숫자를 고정밀도 숫자라고 합니다.
  • 고정밀도 알고리즘은 고정밀도 숫자에 대한 다양한 연산을 처리할 수 있는 알고리즘이지만 그 특수성으로 인해 일반 숫자 알고리즘과 분리되어 자체적인 알고리즘이 됩니다.
  • 고정밀 처리는 실제로 수계산을 시뮬레이션하는 시뮬레이션 방법으로 그 원리는 수직 계산을 사용할 때와 동일하지만 처리 과정에서 고정밀 데이터 읽기, 변환 및 저장에 주의해야 합니다. , 데이터 계산 및 결과 비트 숫자 계산 및 출력 과 같은 여러 문제 .

2. 고정밀도 + 저정밀도

999999999999999999와 같이 큰 숫자가 있고, 6666과 같이 작은 숫자가 있습니다. 이 두 숫자를 어떻게 합치나요?

고정밀 추가 아이디어

  1. 큰 숫자를 문자열에 저장합니다.

  2. 문자열의 각 문자 번호는 ASCII 변환을 통해 배열에 저장됩니다.
    배열의 시작 부분에 하위 비트가 있어야 합니다. a[i] = s[len-i-1]-'0';

  3. 덧셈과 올림 계산:
    ① a[i+1] += a[i]/10,
    ② a[i] %= 10;

  4. 숫자 오버플로, 길이 +1;

  5. 역방향 출력 결과;

C++ 언어 프로그래밍을 예로 들어 어떻게 수행하는지 살펴보겠습니다.

#include<iostream>
#include<string>
using namespace std;
string s1;
int a[1000],b; 
int main(){
    
    
	cin>>s1>>b; // 1.输入数值 

코드에서 s1 배열은 큰 숫자를 저장하고 b 정수는 소수를 저장합니다.
① 1234 + 66
② 123456 + 99
수학적 덧셈 연산에 따르면 단위의 자리와 단위의 자리가 먼저 더해지게 되는데, 즉
① s1[3] + 6
② s1[5] + 9
위에서부터 가 가능하다. 단위 숫자 + 단위 숫자의 색인 첨자가 일치하지 않아 프로그래밍이 어려워지는 것을 확인했습니다. 그런 다음 배열을 역순으로 저장하는 것을 고려할 수 있습니다! 한 자리 숫자는 배열의 시작 부분인 s1[0]에 위치하며, 값이 아무리 크더라도 배열 첨자는 s1[0]으로 시작하여 덧셈을 수행합니다.

//	s1存到数组a里面,记得转为整数
	int len1 = s1.size(); //获取长度
	for(int i=0;i<len1;i++){
    
    
		a[i] = s1[len1-i-1]-'0';
	} 

s1은 문자열이고 ASCII 코드 테이블을 통해 정수로 변환해야 하므로 -'0'을 빼야 합니다.

좋아, 위에서 우리는 배열에 큰 숫자를 저장하는 것을 완료했으며 그런 다음 추가 작업을 수행해야 합니다.

  • a[0] 위치에 먼저 소수점을 추가합니다. a[0] +=b;예: 1234 + 89 =》a[0] = 1323;
  • 그런 다음 새 한 자리를 [0]에 그대로 두고 다른 숫자에 대해 캐리 연산을 수행합니다.
a[0+1] += a[0] /10; // a[1] = 3+132 = 135  
a[0] = a[0] % 10; // a[0] = 3
  • 비유하자면 십의 자리가 업데이트되고 다른 자리가 수행됩니다.
	//3.进行加法运算。
	a[0]+=b; // 5+9999 10004
	//4.进位操作
	for(int i=0;i<len1;i++){
    
    
		a[i+1] += a[i] / 10;
		a[i] = a[i] % 10;
	}

덧셈 연산 후에는 숫자 오버플로 상황을 고려해야 합니다(예: 999 +11 == 1010에는 천 자리가 추가됩니다). 이 문제의 해결 방법은 간단합니다. 가장 높은 비트가 0이 아닌지 확인하고, 조건이 만족되면 캐리 연산을 다시 수행하면 됩니다!

	//5.考虑到数字溢出 
	while(a[len1]){
    
    
		a[len1+1] += a[len1]/10;
		a[len1] %= 10;
		len1++;
	} 

결과를 출력할 때, 결과를 반대로 하는 것을 기억하세요. 이전에는 a[0]이 가장 낮은 비트이고 출력은 왼쪽에서 오른쪽으로 높은 비트에서 낮은 비트로 이루어지기 때문입니다.

	//6.反向输出
	for(int i=len1-1;i>=0;i--){
    
    
		cout<<a[i];
	}

고정밀도 + 저정밀도의 전체 코드는 다음과 같습니다.

#include<iostream>
#include<string>
using namespace std;
string s1;
int a[1000],b; 
int main(){
    
    
	cin>>s1>>b;
//	s1存到数组a里面,记得转为整数
	int len1 = s1.size();
	for(int i=0;i<len1;i++){
    
    
		a[i] = s1[len1-i-1]-'0';
	} 
	//3.进行加法运算。
	a[0]+=b; // 5+9999 10004
	//4.进位操作
	for(int i=0;i<len1;i++){
    
    
		a[i+1] += a[i] / 10;
		a[i] = a[i] % 10;
	}
	//5.考虑到数字溢出 
	if(a[len]){
    
    
		len++;
	} 
	//6.反向输出
	for(int i=len1-1;i>=0;i--){
    
    
		cout<<a[i];
	}
} 

여기에 이미지 설명을 삽입하세요.


3. 고정밀도 + 고정밀도

위와 비슷한 단계입니다.

고정밀 추가 아이디어:

  1. 큰 숫자를 문자열에 저장합니다.
  2. 문자열의 각 문자 번호는 ASCII 변환을 통해 배열에 저장됩니다.
    배열의 시작 부분에 하위 비트가 있어야 합니다. a[i] = s[len-i-1]-'0';
  3. 최대 숫자 길이를 얻으십시오: max(len1,len2);
  4. 덧셈과 올림 계산:
    ① a[i+1] += a[i]/10,
    ② a[i] %= 10;
  5. 숫자 오버플로, 길이 +1;
  6. 역방향 출력 결과;
#include<iostream>
#include<string>
using namespace std;
string s1,s2;
int a[10000],b[10000],c[100001];
int main(){
    
    
//	1.输入值,长度 
	cin>>s1>>s2;  
	int len1 = s1.size();
	int len2 = s2.size(); 
//	2.把字符转为整数存到数组
//  注意要个位存到数组开头 
	for(int i=0;i<len1;i++){
    
    
		a[i] = s1[len1-i-1]-'0';
	} 
	for(int i=0;i<len2;i++){
    
    
		b[i] = s2[len2-i-1]-'0';
	}

두 큰 숫자 모두 문자열로 저장한 다음 정수로 변환해야 합니다. 그러면 배열 첨자는 자릿수에 따라 순차적으로 추가됩니다. 즉, a[i]+b[i]입니다. 추가를 중지할 시기는 길이가 가장 큰 숫자에 따라 결정되므로 추가하기 전에 가장 큰 숫자 길이가 필요합니다.

//	3.获取最大的数。 
	int len = max(len1,len2);
	// 对各个位数进行相加并把最新的值存到输出C里面。
	for(int i=0;i<len;i++){
    
    
		c[i]=a[i]+b[i];
	}

c[i] = a[i]+b[i]를 통해 10보다 큰 c[0] = 11과 같은 상황이 있을 수 있으며 캐리가 필요합니다!

	//4.进位
	for(int i=0;i<len;i++){
    
    
		c[i+1] += c[i]/10;
		c[i] %= 10; 
	}

여전히 마찬가지입니다.캐리 이후 오버플로 문제를 고려하여 출력이 반전됩니다.

	//6.考虑到数字溢出 
	if(a[len]){
    
    
		len++;
	} 
	//7.反向输出 
	for(int i=len-1;i>=0;i--){
    
    
		cout<<a[i];
	}

고정밀 + 고정밀 전체 코드:

/*
高精度的加法思想
	1.把大数存到字符串; 
	2.字符串的每个字符数字都通过ASCII转换存到数组,
	注意的是要低位存在数组开头:a[i] = s[len-i-1]-'0';
	
	3.获取最大的数长度:max(len1,len2) ;
	4.把a,b值加入到c数组: c[i] = a[i]+b[i]; 
	
	5.c数组加法进位的算式:
	①	c[i+1] += c[i]/10; 
	②  c[i] %= 10;
	
	6.数字溢出,长度+1;
	7.反向输出结果;
*/
#include<iostream>
#include<string>
using namespace std;
string s1,s2;
int a[10000],b[10000],c[100001];
int main(){
    
    
//	1.输入值,长度 
	cin>>s1>>s2;  
	int len1 = s1.size();
	int len2 = s2.size(); 
//	2.把字符转为整数存到数组
//  注意要个位存到数组开头 
	for(int i=0;i<len1;i++){
    
    
		a[i] = s1[len1-i-1]-'0';
	} 
	for(int i=0;i<len2;i++){
    
    
		b[i] = s2[len2-i-1]-'0';
	}
//	3.获取最大的数。 
	int len = max(len1,len2);
	// 对各个位数进行相加 
	for(int i=0;i<len;i++){
    
    
		c[i]=a[i]+b[i];
	}
	//4.进位
	for(int i=0;i<len;i++){
    
    
		c[i+1] += c[i]/10;
		c[i] %= 10; 
	}
	//5.溢出
	while(c[len]==0 && len>0){
    
    
		len--;
	} 
	if(c[len]>0){
    
    
		len++;
	} 
	//6.反向输出 
	for(int i=len-1;i>=0;i--){
    
    
		cout<<c[i];
	}
	return 0;
} 

여기에 이미지 설명을 삽입하세요.


4. 고정밀도 뺄셈

이런 식으로 뺄셈이 필요한데, 두 숫자의 뺄셈이 <0인 경우 음수 '-' 기호가 출력되어야 합니다!

고정밀 뺄셈의 아이디어:

  1. 두 개의 큰 숫자를 입력하십시오.

  2. 크기를 결정하려면 s1이 항상 s2보다 크도록 수정하세요.

  3. 길이를 구하세요.

  4. 문자를 정수로 변환: a[i] = s1[len1-i-1]-'0';

  5. 뺄셈 연산:
    ① if(a[i]<b[i]){ a[i+1]–; //상위 비트 – a[i]+=10; //하위 비트+10 } ② c[i] = a[i]-b[i];



  6. 선행 0을 제거하십시오.

  7. 역방향 출력;

자, 값을 입력해 보세요. 처음 입력하는 것은 감수, 두 번째는 감수를 나타냅니다. 뺄셈에는 음수가 나올 것을 알기 때문에 감수 < 감수인 상황을 고려해야 합니다. 즉, 감수의 길이 < 피감의 길이이거나, 길이가 같으면 감수의 길이 < 피감의 값입니다. 그런 다음 '-' 기호를 출력하고 두 값을 교환합니다. 감수는 항상 피감보다 크다는 것을 영구적으로 인식하십시오! ! !

#include<iostream>
#include<string>
using namespace std;
string s1,s2;
int a[10000],b[10000],c[10000];
int main(){
    
    
//	1.输入值
	cin>>s1>>s2;
//	2.判断大小,固定s1恒大于s2 
	if(s1.size()<s2.size() || s1.size()==s2.size() && s1<s2){
    
    
		swap(s1,s2); //交换值
		cout<<"-";
	} 
//	3.获取长度
	int len1 = s1.size(); 
	int len2 = s2.size();  
//	4.字符变整数
	for(int i=0;i<len1;i++){
    
    
		a[i] = s1[len1-i-1]-'0';
	} 
	for(int i=0;i<len2;i++){
    
    
		b[i] = s2[len2-i-1]-'0';
	} 

정수로 변환하여 배열에 저장한 후 뺄셈 연산을 수행하는데, 뺄셈 규칙에 따라 뺄 수가 없으면 +10을 빌려야 하고, 빌려 오면 빼야 합니다. 1. 예를 들어 1234-66입니다. a[0] - b[0] < 0이면 +10, 즉 a[0] + 10을 빌린 다음 b[0]을 빼야 하며, 그러면 a[0+1]–;

	//5.减法运算 
	for(int i=0;i<len1;i++){
    
    
		if(a[i]<b[i]){
    
    
			a[i+1]--; //被借位-- 
			a[i]+=10; // 本位+10 
		}
		c[i] = a[i]-b[i];  //相减结果存到数组c
	} 

123 -120 = 003이면 선행 0을 제거해야 합니다. 그러면 역방향으로 출력됩니다.

	//6.去除前导零
	while(c[len1-1]==0 && len1>1){
    
    
		len1--;
	} 
	//7.反向输出
	for(int i=len1-1;i>=0;i--){
    
    
		cout<<c[i];
	} 

고정밀 뺄셈을 위한 완전한 코드:

/*
高精度减法的思想
	1.输入大数; 
	2.判断大小,固定s1恒大于s2:
	if(s1.size()<s2.size() || s1.size()==s2.size() && s1<s2){
		swap(s1,s2); //交换值
		cout<<"-";
	} 
	3.获取长度;
	4.字符变整数:a[i] = s1[len1-i-1]-'0';
	5.减法运算:
		if(a[i]<b[i]){
			a[i+1]--; //上位-- 
			a[i]+=10; // 本位+10 
		}
		c[i] = a[i]-b[i]; 

	6.去除前导零;
	while(c[len1-1]==0 && len1>1){
		len1--;
	} 
	7.反向输出;
*/
#include<iostream>
#include<string>
using namespace std;
string s1,s2;
int a[10000],b[10000],c[10000];
int main(){
    
    
//	1.输入值
	cin>>s1>>s2;
//	2.判断大小,固定s1恒大于s2 
	if(s1.size()<s2.size() || s1.size()==s2.size() && s1<s2){
    
    
		swap(s1,s2); //交换值
		cout<<"-";
	} 
//	3.获取长度
	int len1 = s1.size(); 
	int len2 = s2.size();  
//	4.字符变整数
	for(int i=0;i<len1;i++){
    
    
		a[i] = s1[len1-i-1]-'0';
	} 
	for(int i=0;i<len2;i++){
    
    
		b[i] = s2[len2-i-1]-'0';
	} 
	//5.减法运算 
	for(int i=0;i<len1;i++){
    
    
		if(a[i]<b[i]){
    
    
			a[i+1]--; //上位-- 
			a[i]+=10; // 本位+10 
		}
		c[i] = a[i]-b[i]; 
	} 
	//6去除前导零
	while(c[len1-1]==0 && len1>1){
    
    
		len1--;
	} 
	//7.反向输出
	for(int i=len1-1;i>=0;i--){
    
    
		cout<<c[i];
	} 
	
	return 0;
} 

여기에 이미지 설명을 삽입하세요.

추천

출처blog.csdn.net/weixin_44775255/article/details/129520783