高精度
总述 (tip: ÷为整除
数据的接收与存储方法
输入的数值没爆范围时,可用数值型变量来接收。但爆了以后,可采用字符串方式
- 利用字符串函数和操作运算
- 直接用循环加数组 输入数据
数串“字符串”形式输入数据,并将其转化为数组来存储
高精度位数的确定
接收时往往采用字符串,所以它的位数就 = 字符串长度。
- 两数之和的位数最大为较大的数的位数+1
- 乘积的位数最大为两个因子的位数之和
- 阶乘与乘方的位数可以采用对数运算来确定计算结果的位数
进位处理和借位处理
- 加法的
c[i] = a[i] + b[i];
if (c[i] >= 10)
{
    c[i] = c[i] % 10;
    c[i + 1] = c[i + 1] + 1;
}- 减法的
if (a[i] < b[i])
{
    a[i + 1] -=  1;
    a[i] += 10;
}
c[i] = a[i] - b[i];- 乘法的
c[i + j - 1] = a[i] * b[j] + x + c[i + j - 1];
x = c[i + j - 1] / 10;
c[i + j - 1] = c[i + j - 1] % 10;- 商和余数
视被除数和除数的位数情况进行处理
- 高精度单精度 从高位相除取余数
- 高精度高精度 再用高精度减法,再统计相减次数
存储输出的位数字
结果的输出
小数点的位置、处理多于的0
高精度加法
要解决的问题:
- 数据的输入
- 数据的存储
- 加法运算,注意进位处理
- 结果的输出
高精度数的输入和保存
输入要符合数字的输入规律:连续输入,中间无空格。字符串读入,数组保存。
cin >> s1 >> s2;
la = s1.size();
lb = s2.size();
for (int i = la - 1; i >= 0; i--) a[la - i - 1] = s1[i] - '0';
for (int i = lb - 1; i >= 0; i--) b[lb - i - 1] = s2[i] - '0';//从0开始加法运算时的进位
if(la > lb) len = la;
else len = lb; //len是较大位数
m = 0;//进位方法一:
for (int i = 0; i < len; i++)
{
	c[i] = (a[i] + b[i] + m) % 10;
    m = (a[i] + b[i] + m) / 10;
}
    //最后一个进位m的处理
if (m > 0)//m = 1
{
	c[len++] = m;
}   方法二
for (int j = 0; j < len; j++)//先逐位相加
{
    c[i] = a[i] + b[i];
}
for (int i = 0; i < len; i++)//从低位依次处理低位
{
    c[i + 1] += c[i] / 10;
    c[i] %= 10;
}
if (c[len + 1] > 0) len = len + 1;//进位
方法三
//a = a + b; 节省空间,省去数组c
for (int i = 0; i < len; i++)
{
    a[i + 1] += (a[i] + b[i]) / 10;
    a[i] = (a[i] + b[i]) % 10;
}
if (a[len + 1] > 0) len +=  1; 运算结果的输出
- 
for (int i = len - 1; i >= 0; i--)
- 
for (int i = len - 1; i >= 1; i--)
- 
cout << c[0]
如果数据变态的出了0001和0002这样的话……
for (int j = len - 1; j >= 0; j--)
{
    if (c[j] == 0)
        t++;
    if (c[j] != 0)
        break;
}
if (t == len) //放置判0把答案0删除
{
    cout << 0 << endl;
    return 0;
}
for (int i = len - 1 - t; i >= 0; i--)//判0
{
    cout << c[i];
}
高精度减法
需要解决的问题
- 比较 和 的大小 从而确定结果的正负号
- 借位问题
- 去掉结果前面多余的0
具体步骤
- 比较  和  的大小 确定结果的正负号谁减谁
cin >> s1 >> s2;
if (s1 == s2) 
{
	cout << "0" << endl;
    return 0;
}
la = s1.size();
lb = s2.size();
if (la < lb || ((la == lb) && (s1 < s2)))
{
	fh = '-';
    s = s1;
    s1 = s2;
    s2 = s;
}
la = s1.size();
lb = s2.size();//la绝对值大 
for (int i = la - 1; i >= 0; i--) a[la - i - 1] = s1[i] - '0';
for (int i = lb - 1; i >= 0; i--) b[lb - i - 1] = s2[i] - '0';
k = la - 1;//数组从0开始- 借位问题
for (int t = 0; t < la; t++)
{
	if (a[t] < b[t])
	{
		a[t + 1] -= 1;
		a[t] += 10;
	}
	a[t] -= b[t];
}- 去掉结果前面多余的
while (a[k] == 0) k--;高精度乘法
单精度×高精度
方法
- 的每一位都单独与 相乘
- 由低到高位依次再处理 的进位
- 处理最高位
参考程序
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
long long b, m;
long long a[260];
int main()
{
    int len;
    string s;
    cin >> s >> b;
    if (b == 0 || s == "0")
    {
        cout << 0 << endl;
        return 0;
    }
    len = s.size();
    for (int i = 1; i <= len; i++)
        a[i] = s[len - i] - '0';
    for (int i = 1; i <= len; i++)
        a[i] *= b;//逐位乘b
    for (int k = 1; k <= len; k++) //处理进位
    {
        a[k + 1] += a[k] / 10;
        a[k] = a[k] % 10;
    }
    m = a[len + 1];
    while (m)
    {
        len++;
        a[len] = m % 10;
        m /= 10;
    }
    for (int y = len; y >= 1; y--)    cout << a[y];
    return 0;
}高精度×高精度
见板子
高精度除法
高精度÷单精度
1. 输入与储存
单精度可以直接读入,高精度的输入与存储同加法运算,仍用存储数的个位
2. 计算结果的位数
除法运算的结果的位数最大等于被除数的位数
3. 除法计算以及商与余数的处理
参与运算的数据:
- 
1个不变的数:除数 
- 
3个变化的数:被除数 、商 和余数 已知被除数(高精度数)存储在数组中,放的是被除数的个位,放的是被除数的最高位,根据除法运算的规则,应该从被除数的最高位开始除以除数,采取按位相处的方法 商 余数 % 将 重新作为被除数,再继续以上步骤,直到被除数() 的每一位都除完为止 过程如下: 
d = 0;
for (int i = len; i >= 1; i--)
{
    d = d * 10 + a[i];
    c[i] = d / b;//商
    d = d % b;//余数
}4.结果的输出商放在数组 中,注意商中要去掉高位的0,确定好输出的位置,余数直接输出 即可
参考程序
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
	const int maxn = 2000;
	string sa;//被除数
	int b, d;//b为除数,d为余数
	int la, len;
	int a[maxn], c[maxn];
	
	cin >> sa >> b;
	
	la = sa.size();
	
	for (int i = la; i >= 1; i--)
	{
	    a[la - i + 1] = sa[i - 1] - '0';
	}
	
	len = la;
	d = 0;
	
	for (int i = len; i >= 1; i--)
	{
	    d = d * 10 + a[i];
	    c[i] = d / b;//商
	    d = d % b;//余数
	}
	
	while (len >= 1 && c[len] == 0)
	    len--;
	
	for (int k = len; k >= 1; k--)
	{
	    cout << c[k];
	}
//	if (d) cout << '.' << d << endl;
    return 0;
}在做两个高精度数运算时,存储高精度数的数组元素可以不仅仅只保留一个数字,而采取保留多位数
这样,在做运算(特别是乘法运算)时,可以减少很多操作次数
高精度÷高精度
- 输入与储存
仍用存储数的个位
- 计算结果的位数
除法运算的结果的位数最大等于被除数的位数
- 
除法计算 可采用循环相减的方法,利用高精度减法来实现 - 初始化余数 ,将被除数的最高位 的值赋给余数 的第 位
- 比较余数  和除数  的大小。
- :(高精度乘法),并将被除数的下一个取数()再赋给余数的第位
- :跳出这步,继续
 
- 计算(高精度减法),并将商的当前位 ,判断是否
- 是:继续上一步
- 否:得到商的一位
 
- 返回第二步,继续
- 直至将被除数a的所有数取完并求减法结束为止
 
参考程序
#include <iostream>  
#include <cstring>  
#include <cstdio>  
using namespace std;
const int N = 100001;
int a[N], b[N], res[N * 2];
char x[N], y[N];
int la, lb;
void init()
{
	la = strlen(x);
	lb = strlen(y);
	memset(a,0,sizeof(a));  
    memset(b,0,sizeof(b)); 
    memset(res,0,sizeof(res)); 
    
    for (int i = la - 1; i >= 0; i--) a[la - i - 1] = x[i] - '0';
    for (int i = lb - 1; i >= 0; i--) b[lb - i - 1] = y[i] - '0'; //从0开始
}
int substraction(int *p1,int *p2,int len1,int len2)
//计算长度为len1的大整数减去长度为len2的大整数的结果的长度 
{
	//减的结果放在数组p1中,不够返回-1,正好返回0 
	if (len1 < len2) return -1;
	bool flag = 0;
	if (len1 == len2)
	{
		for (int i = len1 - 1; i >= 0; i--)
		{
			if (p1[i] > p2[i]) flag = 1;
			else if (p1[i] < p2[i])
			{
				if (!flag) return -1;
			}
		}
	}
	
	for (int i = 0; i < len1; i++)
	{
		p1[i] -= p2[i];
		if (p1[i] < 0)
		{
			p1[i] += 10;
			p1[i + 1]--;
		}
	}
	for (int i = len1 - 1; i >= 0; i--)
	{
		if (p1[i]) return i + 1;
	}
	return 0;
}
void output()
{
	for (int i = 0; i < N; i++)
	{
		if (res[i] >= 10)//进位 
		{
			res[i + 1] += res[i] / 10;
			res[i] %= 10;
		}
	}
	
	bool flag = 0;
	for (int i = N - 1; i >= 0; i--)
	{
		if (flag) cout << res[i];
		else if (res[i])
		{
			cout << res[i];
			flag = 1;
		}
	}
	
	if (!flag) cout << 0;
	
	cout << endl;
}
void divv()
{
	init();
	
	if (la < lb)
	{
		cout << 0 << endl;
		return;
	}
	
	la = substraction(a, b, la, lb);
	if (la < 0)
	{
		cout << 0 << endl;
		return;
	}
	else if (la == 0)
	{
		cout << 1 << endl;
		return;
	}
	
	res[0]++;//减掉一次了,商+1
	int k = la - lb;
	if (k < 0)//减一次后不能再减了 
	{
		output();
		return;
	}
	else if (k > 0)//将数组b乘以10的某次幂,使得其长度与数组a相同
	{
		for (int i = la - 1; i >= 0; i--)
		{
			if (i >= k) b[i] = b[i - k];
			else b[i] = 0;
		}
	}
	
	lb = la;
	for (int i = 0; i <= k; i++)//先减去若干个b*(10^k),不够减了再减去若干个b*(10^(k-1))
	{
		int temp;
		while ((temp = substraction(a, b + i, la, lb - i)) >= 0)//一直减到不够减为止
		{
			la = temp;
			res[k - i]++; //每成功减一次,则商的相应位+1
		}
	}
	output();
}
int main()
{
	scanf("%s %s", x, y); 
	divv();
	//init();
	//for (int i = 0; i < la; i++) cout << a[i];
	return 0;
}#include <iostream>  
#include <cstring>  
#include <cstdio>  
using namespace std;
const int N = 100001;
int a[N], b[N], res[N * 2];
char x[N], y[N];
int la, lb;
void init()
{
	la = strlen(x);
	lb = strlen(y);
	memset(a,0,sizeof(a));  
    memset(b,0,sizeof(b)); 
    memset(res,0,sizeof(res)); 
    
    for (int i = la - 1; i >= 0; i--) a[la - i] = x[i] - '0';
    for (int i = lb - 1; i >= 0; i--) b[lb - i] = y[i] - '0';//从1开始
}
int substraction(int *p1,int *p2,int len1,int len2)
//计算长度为len1的大整数减去长度为len2的大整数的结果的长度 
{
	//减的结果放在数组p1中,不够返回-1,正好返回0 
	if (len1 < len2) return -1;
	bool flag = 0;
	if (len1 == len2)
	{
		for (int i = len1; i >= 1; i--)
		{
			if (p1[i] > p2[i]) flag = 1;
			else if (p1[i] < p2[i])
			{
				if (!flag) return -1;
			}
		}
	}
	
	for (int i = 1; i <= len1; i++)
	{
		p1[i] -= p2[i];
		if (p1[i] < 0)
		{
			p1[i] += 10;
			p1[i + 1]--;
		}
	}
	for (int i = len1; i >= 1; i--)
	{
		if (p1[i]) return i;
	}
	return 0;
}
void output()
{
	for (int i = 1; i <= N; i++)
	{
		if (res[i] >= 10)//进位 
		{
			res[i + 1] += res[i] / 10;
			res[i] %= 10;
		}
	}
	
	bool flag = 0;
	for (int i = N; i >= 1; i--)
	{
		if (flag) cout << res[i];
		else if (res[i])
		{
			cout << res[i];
			flag = 1;
		}
	}
	
	if (!flag) cout << 0;
	
	cout << endl;
}
void divv()
{
	init();
	
	if (la < lb)
	{
		cout << 0 << endl;
		return;
	}
	
	la = substraction(a, b, la, lb);
	if (la < 0)
	{
		cout << 0 << endl;
		return;
	}
	else if (la == 0)
	{
		cout << 1 << endl;
		return;
	}
	
	res[1]++;//减掉一次了,商+1
	int k = la - lb;
	if (k < 0)//减一次后不能再减了 
	{
		output();
		return;
	}
	else if (k > 0)//将数组b乘以10的某次幂,使得其长度与数组a相同
	{
		for (int i = la; i >= 1; i--)
		{
			if (i > k) b[i] = b[i - k];
			else b[i] = 0;
		}
	}
	
	lb = la;
	for (int i = 0; i <= k; i++)//先减去若干个b*(10^k),不够减了再减去若干个b*(10^(k-1))
	{
		int temp;
		while ((temp = substraction(a, b + i, la, lb - i)) >= 0)//一直减到不够减为止
		{
			la = temp;
			res[k - i + 1]++; //每成功减一次,则商的相应位+1
		}
	}
	output();
}
int main()
{
	scanf("%s %s", x, y); 
	divv();
	//init();
	//for (int i = 0; i < la; i++) cout << a[i];
	return 0;
}