大数运算

11 篇文章 0 订阅

1:大整数加法

#include <iostream>
#include <string.h>//用memset的头文件
#include <string>//用string的头文件;oj上好像不加这个也行
//c++的输入输出
//https://blog.csdn.net/qq_40725780/article/details/81032700

using namespace std;

#define MAX 200
	
unsigned int num[MAX + 10];
unsigned int num1[MAX + 10];

int main()
{
	string str1, str2;
	cin >> str1 >> str2;
	memset(num, 0, sizeof(num));
	memset(num1, 0, sizeof(num1));
	int len = str1.length(); int index = 0;
	for (int i = len - 1; i >= 0; i--)
	{
		num[index++] = str1[i] - '0';
	}
	len = str2.length(); index = 0;
	for (int i = len - 1; i >= 0; i--)
	{
		num1[index++] = str2[i] - '0';
	}

	len = str1.length() > str2.length() ? str1.length() : str2.length();

	for (int i = 0; i < len; i++)
	{
		num[i] += num1[i];
		if (num[i] >= 10)
		{
			num[i] -= 10;
			num[i + 1]++;
		}
	}
	bool flag = false;//去0操作
	for (int i = len; i >= 0; i--)
	{
		if (flag || num[i])
		{
			flag = true;
			cout << num[i];
		}
	}
	if (!flag)
	{
		cout << "0";
	}

	return 0;
}
  1. 大数除法
//基本的思想是反复做减法,看看从被除数里昀多能减去多少个除数,商就是多少。
//一个一个减显然太慢,如何减得更快一些呢?以 7546除以 23为例来看一下:
//开始商为 0。先减去 23的 100倍,就是 2300,发现够减 3次,余下 646。
//于是商的值就增加 300。然后用 646减去 230,发现够减 2次,余下 186,
//于是商的值增加 20。昀后用 186减去 23,够减 8次,因此昀终商就是 328
//思路:所以本题的核心是要写一个大整数的减法函数,然后反复调用该函数进行减法操作。
//计算除数的 10倍、100倍的时候,不用做乘法,直接在除数后面补 0即可。
//https://blog.csdn.net/justidle/article/details/104431257/采用数组实现
#include <iostream>

#include <string.h>

#define MAX_LEN 200

char szLine1[MAX_LEN + 10];

char szLine2[MAX_LEN + 10];

int an1[MAX_LEN + 10]; //被除数, an1[0]对应于个位

int an2[MAX_LEN + 10]; //除数, an2[0]对应于个位

int aResult[MAX_LEN + 10]; //存放商, aResult[0]对应于个位

/* Substract函数:长度为 nLen1的大整数 p1减去长度为 nLen2的大整数 p2

减的结果放在 p1里,返回值代表结果的长度

如不够减返回-1,正好减完返回 0

 p1[0]、p2[0]是个位 */

int Substract(int * p1, int * p2, int nLen1, int nLen2)

{

	int i;

	if (nLen1 < nLen2)

		return -1;

	//下面判断 p1是否比 p2大,如果不是,返回-1

	bool bLarger = false;

	if (nLen1 == nLen2) {

		for (i = nLen1 - 1; i >= 0; i--) {

			if (p1[i] > p2[i])

				bLarger = true;

			else if (p1[i] < p2[i]) {

				if (!bLarger)

					return -1;

			}

		}

	}

	for (i = 0; i < nLen1; i++) { //做减法

		p1[i] -= p2[i]; //要求调用本函数时给的参数能确保当 i>=nLen2时,p2[i] = 0

		if (p1[i] < 0) {

			p1[i] += 10;

			p1[i + 1] --;

		}

	}

	for (i = nLen1 - 1; i >= 0; i--)

		if (p1[i])

			return i + 1;

	return 0;

}

int main()

{

	int t, n;

	char szBlank[20];

	scanf("%d", &n);

	for (t = 0; t < n; t++) {

		scanf("%s", szLine1);

		scanf("%s", szLine2);

		int i, j;

		int nLen1 = strlen(szLine1);

		memset(an1, 0, sizeof(an1));

		memset(an2, 0, sizeof(an2));

		memset(aResult, 0, sizeof(aResult));

		j = 0;

		for (i = nLen1 - 1; i >= 0; i--)

			an1[j++] = szLine1[i] - '0';

		int nLen2 = strlen(szLine2);

		j = 0;

		for (i = nLen2 - 1; i >= 0; i--)

			an2[j++] = szLine2[i] - '0';

		if (nLen1 < nLen2) {

			printf("0\n");

			continue;

		}

		nLen1 = Substract(an1, an2, nLen1, nLen2);

		if (nLen1 < 0) {

			printf("0\n");

			continue;

		}

		else if (nLen1 == 0) {

			printf("1\n");

			continue;

		}

		aResult[0] ++; //减掉一次了,商加 1

		//减去一次后的结果长度是 nLen1

		int nTimes = nLen1 - nLen2;

		if (nTimes < 0) //减一次后就不能再减了

			goto OutputResult;

		else if (nTimes > 0) {//对齐操作

			//将 an2 乘以 10的某次幂,使得结果长度和 an1相同

			for (i = nLen1 - 1; i >= 0; i--) {

				if (i >= nTimes)

					an2[i] = an2[i - nTimes];

				else

					an2[i] = 0;

			}

		}

		nLen2 = nLen1;

		for (j = 0; j <= nTimes; j++) {

			int nTmp;

			//一直减到不够减为止

			//先减去若干个 an2×(10 的 nTimes 次方),

			//不够减了,再减去若干个 an2×(10 的 nTimes-1 次方),......

			while ((nTmp = Substract(an1, an2 + j, nLen1, nLen2 - j)) >= 0) {
				//nTmp代表这次相减之后的返回值的长度:相当于把高位给去掉了

				nLen1 = nTmp;

				aResult[nTimes - j]++; //每成功减一次,则将商的相应位加 1

			}

		}

	OutputResult:

		//下面的循环统一处理进位问题

		for (i = 0; i < MAX_LEN; i++) {

			if (aResult[i] >= 10) {

				aResult[i + 1] += aResult[i] / 10;

				aResult[i] %= 10;

			}

		}

		//下面输出结果

		bool bStartOutput = false;

		for (i = MAX_LEN; i >= 0; i--)

			if (bStartOutput)

				printf("%d", aResult[i]);

			else if (aResult[i]) {

				printf("%d", aResult[i]);

				bStartOutput = true;

			}

		if (!bStartOutput)

			printf("0\n");

		printf("\n");

	}
	system("pause");
	return 0;

}
  1. 算法笔记中关于大数运算的内容
// 大整数运算.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//1:存储:

#include <iostream>
#include<cstdio>
#include<cstring>
char a[1024];
char b[1024];
//1:存储:整数的最高位存储到数组的最高位,字符串进行读入时需要进行反转
struct bign {
	int d[1024];
	int length;
	bign() { //结构体初始化
		memset(d, 0, sizeof(d)); 
		length = 0;
	}
};
bign change(char str[]) {
	bign a;
	a.length = strlen(str);
	for (int i = 0; i < a.length; i++)a.d[i] = str[a.length - 1 - i] - '0';
	/*int j = 0;用两个指针的方法进行扫描就不用计算i
	for (int i = a.length - 1; i >= 0; i--)
	{
		a.d[j++] = str[i]-'0';
	}*/
	return a;
}
//2:大整数的加法
bign add(bign a, bign b)
{
	bign c;
	int carry=0;//carry是进位
	for (int i = 0; i < a.length || i < b.length; i++)//以较长的为界限
	{
		int temp = a.d[i] + b.d[i] + carry;
		c.d[c.length++] = temp %10;
		carry = temp / 10;
	}
	if (carry)c.d[c.length++] = carry;//最后一位进位不为0,则直接复制给结果的最高位
	while (c.length-1>=1&&a.d[c.length-1]==0)
	{
		c.length--;
	}
	return c;
}
//3:高精度减法
//3.1判断数的大小;是否能减;
//3.2进行去重
int compare(bign a, bign b)
{
	if (a.length > b.length)return 1;
	else if (a.length < b.length)return - 1;
	else {
		for (int i = a.length - 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 sub(bign a, bign b)
{
	bign c;
	for (int i = 0; i < a.length || i<b.length; i++)//以较长的为界限
	{
		if (a.d[i] < b.d[i])
		{
			//注意这里不能用i++
			a.d[i + 1]--;
			a.d[i] += 10;
		}
		c.d[i] = a.d[i] - b.d[i];
	}
	while (c.length>1&&c.d[c.length-1]==0)
	{
		c.length--;
	}
	return c;
}
//4:高精度乘法:大数和整数相乘
//4.1步骤:把整数看做一个整体,和大数的每一位相乘再与进位相加,所得的结果的个位数作为该位的结果
//高的部分作为进位
//4.2:如果存在负号,则需要先记下负号,然后取绝对值进行代入
bign multi(bign a, int b)
{

	bign c; int carry = 0;
	for (int i = 0; i < a.length; i++)//以较长的为界限
	{
		int temp = a.d[i] * b + carry;
		c.d[c.length++] = temp % 10;
		temp /= 10;
	}
	while (carry)
	{
		c.d[c.length++] = carry % 10;
		carry /= 10;
	}
	return c;
}
//5:大整数除法
//5.1:上一步的余数*10+该步的位,得到该步临时的被除数,和除数进行对比,如果不够除,则商为0;否则商即为对应的商,余数就是对应的余数
//5.2:进行去0
bign divide(bign a, int b,int &r)//如果多个地方用到,就可以直接对原变量进行修改
{

	bign c; 
	c.length = a.length;//被除数和商的每一位都是一一对应的,所以先令其相等
	for (int i =  a.length; i >=0; i++)//从高位开始
	{
		r = r * 10 + a.d[i];//和上一位遗留的余数进行结合
		if(r<b)c.d[i]=0;
		else {
			c.d[i] = r / b;
			r %= b;
		}
	}
	while (c.length > 1 && c.d[c.length - 1] == 0)
	{
		c.length--;
	}
	return c;
}
void print(bign a) {
	for (int i = a.length - 1; i >= 0; i--)
	{
		printf("%d", a.d[i]);
	}
  /*  prin
  tf("\n");*/
}
int main()
{
	scanf("%s", a);
	scanf("%s", b);
	bign n = change(a);
	bign m = change(b);
	print(add(n, m));
	return 0;
}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值