C++高精度计算(二)
分享内容
- 高精度除法
- 高精度应用
浮点数的精度
C++提供了float和double 两种浮点数类型,用于存储和操作小数。浮点数的精度,即小数部分的长度。C++中的浮点数采用IEEE 754 标准进行存储和表示。尾数位存储浮点数的小数部分,所以浮点数的精度主要由尾数的位数决定的。在IEEE 754标准中,单精度浮点数(float)的尾数有23位,其精度约为7位十进制数字;而双精度浮点数(double)的尾数有52位,精度则提升至约15位十进制数字。
高精度除法(一)
a、b不是高精度整数
问题1:a,b为10^8范围内的非负整数,求a/b保留n位小数的商。(n <= 100)
但是题目要求的商的小数位数非常大,超出了C++浮点型能表示的精度范围。
浮点数的精度主要由尾数的位数决定的。
输出超出浮点数精度的小数位会导致舍入和精度损失。所以不能直接用浮点类型计算和输出本题要求的商。
86÷25
(求小数商)
相当于余数*10
·1、先按照整数除法的法则去除。
·2、除到被除数的末尾仍有余数时,就在余数后面添0,
再继续除。
初始余数是11,
1110=110,110除以25,商4余10(即商的十分位是4,余数
继续参与运算);
1010=100,100除以25,商4余0;(即商的百分位是4)
模拟整数除法求高精度的商
int a,b,n ;
商由整数和小数部分组成。
- 商的整数部分=a/b(整除)。
- 小数部分:
初始余数t=a%b
①那么对应小数位的商为t10/b,输出这个值
②更新余数t=t10%b,余数进行下一轮计算循环执行步骤n次,就可以得到所需的精度
int t = a%b;
for(int i=1;i <= n; i++) {
t *= 10;
cout << t/b;
t %= b;
}
高精度除法(二)
问题2:高精度整数a除以单精度整数b,求商c和余数d。
观察竖式运算
163÷7= 23 … 2
从高位开始 前一位除法的余数10+当前位上的数字
第一步 最高位1:不够除(商0余1);
第二步 前面的余110+6=16,16除以7商2余2
第二步 前面的余2*10+3=23,23除以7商3余2
高精度算法思路:从高精度数的最高位开始,逐位与单精度数进行除法运算。
除法是从高位开始除。所有高精除法的数据存储要正序存放,最高位在最左边。
被除数a是高精度数,需要将a中的每一位数字分别存储在整数数组中。
b是单精度数,可以用一般的整数变量来接收和存储。
int a[MAX];// 整型数组存储商
int b ;//整型变量存储除数
同时定义一个整型数组来存储商,余数一定小于b,所以可以用整型变量保存。
int c[MAX];// 整型数组存储商
int d;//整型变量存储余数

从高位开始逐位进行除法运算:
第i轮运算:
- 将当前处理的位与前一位的余数组合成一个新的数,即t=t*10+a[i]
- t/b即商的当前位,存储在ci
- 将余数存储在t(t=t%b)
伪代码:alen指被除数a的长度
int t=0;// 逐位除法的余数
for(int i=1;i <= alen;i++) {
t = t*10 + a[i];
c[i]= t/b;// 对应位的商
t = t%b;// 更新余数
}
d = t;// 余数
求高精度商
单精度整数,求高精度的商
已知a,b为10^8范围内的非负整数(b != 0),求a除以b保留前n位小数商的结果。(n <= 100)
【输入描述】abn
【输出描述】a除以b保留前n位小数的商
【输入样例】
97 61 50
【输出样例】
1.59016393442622950819672131147540983606557377049180
int a,b,n ;
基本步骤:
-
输出商的整数部分 (a/b)。
-
小数部分:
初始余数t=a%b
① 对应小数位的商为t10/b,输出这个值
② 更新余数t=t10%b,余数进行下一轮计算
循环执行步骤①②n次,就可以得到所需的精度。
完整代码
#include<iostream>
using namespace std;
int main() {
int a,b,n;
cin >> a >> b >> n;
cout << a/b << ".";
int t = a%b;
for(int i=1;i <= n;i++) {
t *= 10;
cout << t/b;
t %= b;
}
return 0;
}

高精度除以单精度
输入一个高精度整数a(不超过100位),和另一个单精度整数b(b不超过
8位),请求出a除以b得到的商和余数各是多少?
【输入描述】输入有2行,第一行有一个正整数a(不超过100位),第二
行有一个正整数b。
【输出描述】输出2行。第一行a除以b的商,第二行余数。
【输入样例】
8162148605591693302243
20136
【输出样例】
405351043185920406
7027
被除数a是高精度数,需要将a中的每一位数字分别存储在整数数组中。
b是单精度数,可以用一般的整数变量来接收和存储。
int a [MAX];// 整型数组存储商
int b ;//整型变量存储除数
同时定义一个整型数组来存储商,余数一定小于b,所以可以用整型变量保存。
int c[MAX];// 整型数组存储商
int d;//整型变量存储余数
1、输入a、b;
初始化c、d;
输入高精度数,正序保存到数组a,输入单精度数,保
存到整数变量b。初始化商数组c所有元素值为0,余数d为0。
2、逐位模拟除
法运算
逐位处理:从高精度数的最高位开始,逐位与单精度数
进行除法运算。
3、输出c、d
输出商(数组c去除前导0后的所有值)和余数d。
1~被除数长度,逐位模拟除法运算的具体步骤:
第i位的运算:
- 将当前处理的位与前一位的余数组合成一个新的数,即t=t*10+a[i]
- t/b即商的当前位,存储在ci
- 将余数存储在t(t=t%b)
a[0]中保存被除数的长度
void div() {
int t=0;//逐位除法的余*
for(int i=1;i <= a[0];i++) {
t=t*10+ a[i];//将当前处理的位与前一位的余数组合成一个新的数
c[i]= t/b;// 商的当前位
t = t%b;// 更新余数
}
d = t;
}
#include<iostream>
#include<cstring>
using namespace std;
int a[110];//被除数
int b;//除数
int c[110];//商
int d;//余数
void init() {
char ac[110];
cin >> ac >> b;
a[0]= strlen(ac);//a高精度数的位数存在a[0]中
for(int i=0;i<a[0];i++)
a[i+1]=ac[i]-'0';//将数字字符串ac转换成数组a,顺序存储数字
}
void div() {
int t=0;
for(int i=1;i <= a[0];i++){//从高位开始逐位进行除法运算
t = t*10 + a[i] ;
c[i] = t/b;
t = tb;
}
d=t;//余数
}
int main() {
init();
div();
c[0]=a[0];//获取最大位数
int i=1;
while(c[i] == 0)//去前导0
i++:
if(i>c[0])//当a<b时,c[]数组全部是0,此时直接输出0
cout << 0;
else
while(i <= c[0]) // 输出商
cout << c[i++];
cout << endl << d << endl;//输出余数
return 0;
}

【注意】当a<b时,商0余数b。
高精度除以单精度-扩展
如果问题变成:高精度数a除以单精度b,求保留n位小数的商。
1、高精度数a除以单精度b,先算出商c,余数d
2、根据余数d继续计算出商的n位小数,此时d是被除数,b是除数
cout << ".";// 先输出小数点
int t = d%b;
for(int i=1;i <= n;i++){//逐位计算输出商的小数位上的值
t *= 10;
cout << t/b;
t %= b;
}
n的阶乘
计算n的阶乘,(1 <= n <= 100)。
【输入描述】只有一行输入,整数n。
【输出描述】输出一行,即n!的值。
【输入样例】
100
【输出样例】
933262154439441526816992388562667004907159682643816214685929638
952175999932299156089414639761565182862536979208272237582511852
10916864000000000000000000000000
【分析】如果手动进行计算,20!大约为2.4*10^18,还可以用long long保存。但是当n>20,n!计算
结果long long就保存不了。所以需要用高精度算法。
100的阶乘有多少位,需要多大的数组?我们可以使用对数的性质来估算。
我们可以使用计算器或编程语言来计算这个和。计算得到:log1o(100!)=157.97
因此,100的阶乘的位数是:157.97向上取整得158。所以,100的阶乘有158位。
#define MAXN 160
int a[MAXN]={0};// 保存阶乘结果

n!的高精度计算的算法步骤
1、初始化a[0]=1,其他元素值=0。
2、输入n。
3、循环进行累乘计算:k=2~n,
初始进位=0;
从低位到高位(i=0~MAXN-1)逐位*k,并处理进位:
① 计算t=a[i]*k+进位。
② 将计算结果t的个位更新到a[i]中,同时更新进位。
4、输出结果:先去除数组a中的前导0,再逆序输出a中的结果。
#define MAXN 160
int a[MAXN]={0};// 保存阶乘结果
int n;
#include<iostream>
using namespace std;
#define MAXN 160
int a[MAXN]={0};
int n;
int main() {
cin >> n;
a[0] = 1;
for(int k = 2;k <= n;k++) {
int up=0;//进位初始为0
for(int i = 0;i<MAXN;i++){//从个位到最高位,处理进位
int t = a[i]*k + up;//逐位*k +进位
a[i] = t%10;// 保存个位
up = t/10;// 留下进位部分
}
}
int i = MAXN-1;
while(a[i] == 0) // 去前导0
i --;
while(i>=0)//输出阶乘结果
cout << a[i -- ];
return 0;
}

阶乘之和
计算阶乘和:1!+2!+3!+4!+ … +n!,(1 <= n <= 50)。
【输入描述】只有一行输入,整数n。
【输出描述】输出一行,即1!+2!+3!+4!+ … +n!的值。
【输入样例】
5
【输出样例】
153
【分析】同样的,当n>20,n!计算结果long long保存不了,阶乘以及阶乘和都需要用高精度计算法
进行处理。
需要定义两个整数数组存放阶乘、阶乘和的高精度计算结果:
#define MAXN 160
int a[MAXN]={0};// 保存阶乘结果
int s[MAXN]={0};// 保存阶乘和的结果
阶乘和的高精度计算的算法步骤
n=1时,阶乘=1,阶乘和=1
1、初始化a[0]=1,s[0]=1。
2、输入n。
3、循环进行计算:k=2~n,
① 计算阶乘k !: 逐位*k,并处理进位,结果保存在a[];
② 计算阶乘和1!+ …. +K !: 逐位累加 s[i]+a[i],并处理进位,结果保存在s[];
4、输出结果:去前导0,逆序输出s中的值。
#define MAXN 160
int a[MAXN]={0};// 保存阶乘结果
int s[MAXN]={0};//保存阶乘和的结果
int n;
完整代码
#include<iostream>
using namespace std;
#define MAXN 160
int a[MAXN]={0};// 保存阶乘
int s[MAXN]={0};//保存阶乘和
int main() {
int n;
cin >> n;
a[0]=1;//初始化 1 != 1
s[0]=1;//n=1的阶乘和=1
for(int k = 2;k <= n;k++) {
// 1.计算阶乘k!
int up= 0;//进位初始为0
for(int i=0;i <MAXN;i++){//从个位到最高位,处理进位
int t= a[i]*k+ up;//逐位*k+进位
a[i] = t$10;// 保存个位
up = t/10;// 留下进位部分
}
//2.累加到s[],得到1!+…+K!
up=0;//进位初始为0
for(int i=0;i <MAXN;i++){//从个位到最高位,处理进位
int t=s[i] + a[i] + up;//逐位累加t=s[i]+a[i]+进位
s[i] = t$10;// 保存个位
up = t/10;// 留下进位部分
}
}
int i = MAXN-1;
while(s[i] == 0) //去前导0
i --;
while(i>=0)//输出阶乘和结果
cout << s[i -- ];
return 0;
}

本次课程的知识点
- 实现高精度除法
- 其他高精度应用:高精度阶乘,高精度阶乘和

【提示】B选项函数缺少返回类型,因此不正确。C选项,返回类型定义为void,这意味着函数不返回任何值,代码尝试将
square(2.0)的结果赋值给area,这会导致编译错误。D选项,return没有返回任何值。A选项,正确定义了一个返回类型为
float的函数square,它接受一个float类型的参数x并返回x的平方。而且调用square(2)并将结果赋值给area是正确的。
2、C++表达式(6>2)*2的值是(B)?
A, 1
B、2
C, true
D. false
【提示】先执行小括号内的运算,6>2这个逻辑比较结果是true,布尔值true等于1,1*2结果为2,所以整个表达式结果为2。
2的n次方
任意给定一个正整数n(n <= 100),计算2的n次方的值。
输入描述】输入一个正整数n。
输出描述】输出2的n次方的值。
【输入样例】
100
(输出样例】
1267650600228229401496703205376
#include<iostream>
using namespace std;
#define MAXN 160
int a[MAXN]={0};
int n;
int main() {
cin >> n;
a[0] = 1;
for(int i = 1;i <= n;i++) {
int up=0;//进位初始为0
for(int j=0;j<MAXN;j++){//从个位到最高位,处理进位
int t=a[j]*2+up;//逐位*2+进位
a[j] = t%10;// 保存个位
up = t/10;// 留下进位部分
}
}
int i = MAXN-1;
while(a[i] == 0) // 去前导0
i --;
while(i>=0)// 输出商
cout << a[i -- ];
return 0;
}

更多推荐



所有评论(0)