高精度算法

目录

高精度加法

算法核心:

高精度减法

算法核心:

高精度乘法

算法核心:

高精度除法

 高精度除以低精度

算法核心:

高精度除以高精度

算法核心:


  • int的范围为[-2^{31},2^{31}-1],为10^{9}数量级;
  • long long的范围为[-2^{63},2^{63}-1],为10^{18}数量级;

高精度加法

  1. 输入两个整数a,b,输出它们的和(a,b< 10^{9})
  2. 输入两个整数a,b,输出它们的和(a,b< 10^{500})

分析:

  1. 可以用long long类型和Int类型直接计算。
  2. 超int和long long的范围了,使用高精度进行求解。数组长度大于500

 问题描述 :A + B =

                     图源:麦克老师讲算法

算法核心:

c[i] += a[i] +b[i] ; //注意 +=  因为要加上进位。

c[i+1] =c[i] / 10;  //进位。

c[i] =c[i] %10]   //要舍去进位的那部分

将数值转置再计算。

1234+ 567   转过来  4321 +765  [0]位 4+7 , [1]位 3+6  

P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<iomanip>
#include<math.h>
#include<algorithm>
#include<string>
#include<cstring>
#include<stdio.h>
using namespace std;

int main()
{
	//按字符数组输入,再存到数组里。
	int a[505], b[505],c[505],la,lb,lc;
	memset(a, 0, sizeof(a));
	memset(b, 0, sizeof(b));
	memset(c, 0, sizeof(c));//数组如果后续需要对本身进行运算,一定要记得初始化为0。
	string s1, s2;
	cin >> s1;
	getchar();
	cin >> s2;

	la = s1.size();
	lb = s2.size();
	
	for (int i = 0; i < la; i++)
		a[la - i-1 ] = s1[i] - '0';	//比如 1234  输入的时候 1是s1[0]  要把 1换为最高下标,4换为最小下标
	for (int i = 0; i < lb; i++)
		b[lb - i-1 ] = s2[i] - '0';
		
	lc = max(la, lb) + 1; 

	for (int i = 0; i < lc; i++)
	{
		c[i] += a[i] + b[i];	
		c[i + 1] = c[i] / 10;
		c[i] = c[i] % 10;
	}

	if (c[lc-1] == 0 && lc > 0) lc--;//删除前导0

	for (int i = lc-1; i >= 0; i--)
		printf("%d", c[i]); //从最高下标开始输出 

	return 0;
}

高精度减法

问题描述: A - B =

        图源:麦克老师讲算法

算法核心:

  1. 如果a<b,交换a,b
  2. 如果a[i]<b[i],高位借一当十

if(a[i]<b[i])

{

     a[i+1]--;  //因为a[i]向a[i+1]借1,所以a[i+1]要减1

     a[i]=a[i]+10;

}

c[i] = a[i] - b[i] ;

P2142 高精度减法 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<iomanip>
#include<math.h>
#include<algorithm>
#include<string>
#include<cstring>
#include<stdio.h>
using namespace std;

int main()
{
	//按字符数组输入,再存到数组里。
	int a[10100], b[10100],c[10100],la,lb,lc,i=0;
	memset(a, 0, sizeof(a));
	memset(b, 0, sizeof(b));
	memset(c, 0, sizeof(c));//数组一定要记得初始化为0。
	string s1, s2;
	cin >> s1;
	cin >> s2;
	if (s1 == s2)
		cout << 0;
	else
	{
		if (s1.size() < s2.size() || (s1.size() == s2.size() && s1[0] < s2[0]))
		{
			cout << "-";
			swap(s1, s2);
		}

		la = s1.size();
		lb = s2.size();

		for (int i = 0; i < la; i++)
			a[la - i - 1] = s1[i] - '0';
		for (int i = 0; i < lb; i++)
			b[lb - i - 1] = s2[i] - '0';

		lc = max(la, lb);

		for (int i = 0; i < lc; i++)
		{
			if (a[i] < b[i])
			{
				a[i + 1]--;//因为a[i]向a[i+1]借1,所以a[i+1]要减1
				a[i] += 10;
			}
			c[i] = a[i] - b[i];
		}

		while (c[lc - 1] == 0) lc--;//删除前导0

		for (int i = lc - 1; i >= 0; i--)
			printf("%d", c[i]);
	}
	return 0;
}

高精度乘法

                            图源:麦克老师讲算法

算法核心:

c[i+j-1]+=a[i]*b[j];

c[i+j]+=c[i+j-1]/10;    // 进位

c[i+j-1]%=10;

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<iostream>
#include<iomanip>
#include<math.h>
#include<algorithm>
#include<string>
#include<cstring>
#include<stdio.h>
using namespace std;

int main()
{
	//按字符数组输入,再存到数组里。
	int a[105], b[105],c[10000],la,lb,lc;
	memset(a, 0, sizeof(a));
	memset(b, 0, sizeof(b));
	memset(c, 0, sizeof(c));//数组一定要记得初始化为0。
	string s1, s2;
	cin >> s1;
	cin >> s2;
	if (s1 == "0"||s2 =="0")
		cout << 0;
	else
	{
		la = s1.size();
		lb = s2.size();

		for (int i = 0; i < la; i++)
			a[la - i-1 ] = s1[i] - '0';
		for (int i = 0; i < lb; i++)
			b[lb - i-1 ] = s2[i] - '0';

		for (int i = 0; i < la; i++)
		{
			for (int j = 0; j < lb; j++)
			{
				c[i + j ] += a[i] * b[j]; // 0+0-1小了!!!  不能i+j-1那样算。
				c[i + j+1] += c[i + j ] / 10;
				c[i + j ] %= 10;
			}
		}
	
		lc = la + lb ;
		while (c[lc] == 0&&lc>0) lc--;
		for (int i = lc; i >= 0; i--)
			printf("%d", c[i]);
	}
	return 0;
}

若以上代码i+j部分写为i+j-1,会报错 

高精度除法

 高精度除以低精度

                                                  图源:麦克老师讲算法 

逐位试商法

算法核心:

c[i] = (x * 10 + a[i]) / b;
x = (x * 10 + a[i]) % b;

P1480 A/B Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
char s[5005];
long long a[5005] = { 0 }, c[5005] = { 0 };
long long b, la, x = 0, lb = 0;
int main()
{
	cin >> s >> b;
	la = strlen(s);
	for (int i = 0; i < la; i++) a[i] = s[i] - '0';
	for (int i = 0; i < la; i++)
	{
		c[i] = (x * 10 + a[i]) / b;
		x = (x * 10 + a[i]) % b;
	}
	while (c[lb] == 0 && lb < la-1) lb++; //删除前导0 
	for (int i = lb; i < la; i++) cout << c[i];
	return 0;
}

高精度除以高精度

                                          图源:麦克老师讲算法

算法核心:

减法模拟除法

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
char s1[305], s2[305];
int a[305], b[305], c[305], tmp[305];//a为被除数 b为除数 c为商
//运算从1开始,0没有用到。[0]可以放数组位数。
void init(int *x)
{
	char s[305];
	cin >> s;
	x[0] = strlen(s);
	for (int i = 0; i < x[0]; i++)
	{
		x[x[0] - i] = s[i] - '0';
	}
	//要做减法,倒序存储字符数组。
}

int compare(int a[],int b[])
{
	if(a[0] > b[0]) return 1;//比较a和b的位数。如果a的位数大于b的位数,那么a>b
	if (a[0] < b[0]) return -1;
	for (int i = a[0]; i > 0; i--)
	{
		if (a[i] > b[i]) return 1;
		if (a[i] < b[i]) return -1; 
	}//若位数一样,比较最高位,最高位若一样,比较次一位。
	return 0;
}

void jian(int a[], int b[])
{
	for (int i = 1; i <= a[0]; i++)
	{
		if (a[i] < b[i])
		{
			a[i + 1]--;
			a[i] = a[i] + 10;
		}
		a[i] = a[i] - b[i];
	}
	while (a[a[0]] == 0 && a[0] > 0) a[0]--;//删除前导0
}

void numcpy(int p[], int q[], int n)
{
	for (int i = 1; i <= p[0]; i++) q[i + n - 1] = p[i];
	q[0] = p[0] + n - 1;
}//已经转置了,  左移n位。将q整体移动n位放到q数组里。

void print(int a[])
{
	if (a[0] == 0) { cout << 0; return; }
	for (int i = a[0]; i > 0; i--) cout << a[i];
	return;
}
int main()
{
	memset(a, 0, sizeof(a));
	memset(b, 0, sizeof(b));
	init(a);//输入a
	init(b);//输入b
	memset(c, 0, sizeof(c));
	c[0] = a[0] - b[0] + 1;//商的位数。
	//如果被除数首位 > 除数的首位,则商的位数 = 被除数位数-除数的位数+1;
	//如果被除数首位 < 除数的首位,则商的位数 = 被除数位数-除数的位数
	//被除数首位 = 除数的首位, 要看两者的次位,以此类推。
	for (int i = c[0]; i >= 1; i--)
	{
		memset(tmp, 0, sizeof(tmp));
		numcpy(b, tmp, i);
		while (compare(a, tmp) >= 0)
		{
			c[i]++;//减几次c[i]就是几。
			jian(a, tmp);//减几次。
		}
	}
	while (c[c[0]] == 0 && c[0] > 0) c[0]--;//去除前导0
	print(c);//商
	cout << endl;
	print(a);//余数
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值