高精度运算

前言

在C++中类型定义的话,对于数据是有较严格要求的。
int类型 在内存中的大小为4byte 范围是-231~231-1
long long 类型 在内存中大小为 8byte 范围是 -263-263-1
简单解释一下啊:
计算机在存储时使用的最小单位是"位",一位存储的是0或是1,一位就是bit。也就是二进制存储。
还有一个概念叫“字节”(byte) 1byte=8bit。
所以int可以存到32bit,但是有一位要留给正负号,所以是31,然后由于还有一个特殊的数0,而0~231-1刚好是231个数。最多表示10位整数。
long long就是-263~263-1。最多表示19位整数。

加法

模拟过程:由于计算是从右向左计算的,进位各种的不太方便。而且字符串每一位只能存入一位字符,所以采用整数数组来存储。为了让计算从左到右进行,打算把两个字符串逆序存入两个整数数组,逐位运算,逐位进位即可。

#include <iostream>
#include <math.h>
using namespace std;
int main() {
	string s1, s2; //将两个高精度的数存入字符串中
	cin >> s1 >> s2; //如果没有空格的话推荐使用cin输入
//好像说getline在OJ上会误错
	int nums1[1000] {0}, nums2[1000] = {0}; //开一个1000的数组将s1与s2逆序存入其中
	int len1 = s1.size(), len2 = s2.size(); //提前声明,减少循环次数
	for (int i = 0; i < len1; ++i) {
		nums1[i] = s1[len1 - 1 - i] - '0'; //由于取出的字符串是字符所以要减去对应的ASCII码
	}
	for (int i = 0; i < len2; ++i) {
		nums2[i] = s2[len2 - 1 - i] - '0';
	}
	//再开一个数组用于记录相加的位数,还要定义一个整数len为len1与len2的最大值,因为要加len次
	int num[1000] = {0}, len = max(len1, len2);
	int a = 0; //还要定义一个整数用于记录数组的长度
	for (a; a < len; ++a) {
		num[a] = nums1[a] + nums2[a]; //先加再进位
	}
	//进位
	for (int i = 0; i < a - 1; ++i) {
		if (num[i] >= 10) {
			num[i] %= 10;
			num[i + 1] += 1;
		}
	}
	//倒序输出
	//如果首位进位了的话不能保证输出,所以加了一个判断
	if (num[a] != 0) {
		cout << num[a];
	}
	for (int i = 0; i < a; i++) {
		cout << num[a - 1 - i];
	}
}

减法

减法基本思路跟加法相同,也是逆序存入数组然后每一位对应先减后进位。但是要注意的是,有可能出现结果为负数的情况,所以需要判断一下然后逆过来减。也可以在起初的时候判断s1与s2哪个大,然后交换一下。

#include <iostream>
#include <math.h>
using namespace std;
int main() {
	string s1, s2; //将两个高精度的数存入字符串中
	cin >> s1 >> s2; //如果没有空格的话推荐使用cin输入
	int nums1[1000] = {0}, nums2[1000] = {0}; //开一个1000的数组将s1与s2逆序存入其中
	int len1 = s1.size(), len2 = s2.size(); //提前声明,减少循环次数
	for (int i = 0; i < len1; ++i) {
		nums1[i] = s1[len1 - 1 - i] - '0'; //由于取出的字符串是字符所以要减去对应的ASCII码
	}
	for (int i = 0; i < len2; ++i) {
		nums2[i] = s2[len2 - 1 - i] - '0';
	}
	int num[1000] = {0}, len = max(len1, len2);
	int a = 0;
	if (len1 > len2 || (len1 == len2 && s1 > s2)) {
//当s1对应的数大于s2的时候
		for (a; a < len; ++a) {
			num[a] = nums1[a] - nums2[a];
		}
	} else if (len1 < len2 || (len1 == len2 && s1 < s2) ) {
//当s1对应的数小于s2的时候
		for (a; a < len; ++a) {
			num[a] = -nums1[a] + nums2[a];
		}
		cout << '-';//输出负号
	} else if (s1 == s2) {
//会存在一个特殊情况就是s1等于s2的时候返回很多个0,所以单独拎出来
		cout << '0';
		return 0;//直接结束main主函数
	}
	for (int i = 0; i < a; ++i) {
		if (num[i] < 0) {
			num[i] = 10 + num[i];
			num[i + 1] = num[i + 1] - 1;
		}
	}
	//找到第一个不为0的数,因为减法可能到最后只剩一位数
	for (int j = 0; j < a; ++j) {
		if (num[a - 1 - j] != 0) {
			a = a - j;
			break;
		}
	}
	for (int i = 0; i < a; ++i) {
		cout << num[a - 1 - i];
	}
}

高精度乘以单精度

还是一样,逐位相乘与此同时进位,需要注意的是,这个算法在最后一个格子中得到的数不需进位直接输出即可。比如986*26,我们会得到6 3 6 25,这个数组,直接逆序输出就可以了,不需要再将25进位为6 5 6 5 2,反而略显麻烦。

#include <iostream>
using namespace std;
int nums1[1000], num[1000];
int main() {
	string s1;
	int a;
	cin >> s1 >> a;
	if (a == 0) {
		cout << '0';
		return 0;
	}
	int len1 = s1.size();
	for (int i = 0; i < len1; ++i) {
		nums1[i] = s1[len1 - 1 - i] - '0';
	}
	int i = 0;
	for (i; i < len1; ++i) {
		num[i] += nums1[i] * a;
		if (num[i] >= 10) {
			num[i + 1] += num[i] / 10;
			num[i] %= 10;
		}
	}
	if (num[i] != 0) {
		cout << num[i];
	}
	for (int j = 0; j < i; ++j) {
		cout << num[len1 - j - 1];
	}
}

高精度乘高精度

高精度乘法也是一样的,只不过进位需要注意一下。由于每个位数的乘法都需要进1,所以在双循环的时候采用的是u+v,注意两个len1,len2长的整数相乘,最长是len1+len2,所以要从最后一位往会判断看看首个不为0的是哪个,再从这位开始逆序输出。

int nums1[1000], nums2[1000], num[1000];//全局变量 为了内部元素全为0
int i;
int main() {
	string s1, s2;
	cin >> s1 >> s2;
	if (s1 == "0" || s2 == "0") {
		cout << '0';
		return 0;
	}
	int len1 = s1.size(), len2 = s2.size();
	for (i = 0; i < len1; ++i) {
		nums1[i] = s1[len1 - 1 - i] - '0';
	}
	for (i = 0; i < len2; ++i) {
		nums2[i] = s2[len2 - 1 - i] - '0';//一定要注意ASCII码转码!!
	}
	int u = 0, v = 0;
	for (u = 0; u < len1; ++u) {
		for (v = 0; v < len2; ++v) {
			int a = nums1[u] * nums2[v];
			num[v + u] += a;
//由于乘法需要进位 外层每过去一位都需要进1 所以这里进位与u相关联
			if (num[u + v] >= 10) {
				num[u + v + 1] += num[u + v] / 10;
				num[u + v] %= 10;
			}//由于存入了一个新的数组,所以可以边算边进位
		}
	}
	int a = u + v - 1;//逆序查找 数组下标需要减1
	for (a; a >= 0; --a) {
		if (num[a] != 0) {
			i = a;//找到逆序第一个不为0的数
			break;
		}
	}
//从i位开始输出
	for (int j = 0; j <= i; ++j) {
		cout << num[i - j];
	}
}

高精度除法

高精度除法有两种,第一种是有时候对于较小的数要求精确到小数点后100位,第二种是大数运算。
第一种的代码 逐步取余模拟即可

#include <iostream>
using namespace std;
int main() {
	int a, b, n, t = 0, i = 0;
	cin >> a >> b >> n;
	cout << a / b << '.';
	t = a % b * 10;
	for (i; i < n; i++) {
		cout << t / b;
		t = (t - t / b * b) * 10;
	}
}

第二种代码
这个是大数除以一个精确数的,这个方法要笨一点,要把几种极端点的情况用if列出来

#include <iostream>
#include <string.h>
using namespace std;

int main() {
	string s1;
	int B, num1[2000] = {0}, num2[2000] = {0}, i = 0;
	cin >> s1 >> B;
	int len = s1.size();
	//cout << len;
	//把精确大数逐个输入整数数组
	for (int i = 0; i < len; ++i) {
		num1[i] = s1[i] - '0';
	}
	//判断特殊情况
	if (num1[i] == 0) {
		cout << '0';
	} else if (num1[i] < B && len == 1) {
		cout << '0';
	} else if (num1[i] == B && len == 1) {
		cout << "1 0";
		return 0;
	}
	//如果是一位数的话就不会进入这个循环
	while (i < len - 1) {
		if (num1[i] >= B) {
			num2[i] = num1[i] / B;
			num1[i] -= num2[i] * B;
		} else {
			int a = num1[i] * 10 + num1[i + 1];
			num2[i + 1] = a / B;
			num1[i + 1] = a - num2[i + 1] * B;
			i++;
		}
	}
	for (int j = 0; j < len; j++) {
		if (num2[0] == 0) {//因为最多只可能第一位为0
			num2[0] = 1;
		} else {
			cout << num2[j];
		}

	}
	cout << " ";
	cout << num1[i];
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一袍清酒付825

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值