第1章 高精度计算
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<iostream> #include<cstring> using namespace std; int main() {
int a[10001]={0},b[10001]={0},c[10001]={0}; char n[10001],n1[10001],n2[10001]; cin>>n1; //输入被减数 cin>>n2; //输入减数 if (strlen(n1)<strlen(n2)||(strlen(n1)==strlen(n2)&&strcmp(n1,n2)<0)) //strcmp()为字符串比较函数,当n1==n2, 返回0; //n1>n2时,返回正整数;n1<n2时,返回负整数 { //处理被减数和减数,交换被减数和减数
第一章 高精度计算
利用计算机进行数值计算,有时会遇到这样的问题:有些计算要求精度高,希望计算 的数的位数可达几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的 限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高 精度计算。介绍常用的几种高精度计算的方法。
高精度计算中需要处理好以下几个问题:
init(a); init(b); add(a,b); for(int i=c[0];i>=1;i--)cout<<c[i]; return 0; }
void init(int a[]){ //传入一个数组
char s[10001]; cin>>s; //读入字符串s a[0]=strlen(s); //用a[0]计算字符串s的位数
}
if(x>0)c[i]=x; else i--; while(c[i]==0&&i>1)i--;//最高位的0不输出
c[0]=i;
}
【例2】高精度减法。输入两个正整数,求它们的差。
【算法分析】 类似加法,可以用竖式求减法。在做减法运算时,需要注意的是:被减数必须比减数大,同时需要处理借位。
减法借位:if (a[i]<b[i]) { --a[i+1]; a[i]+=10; } c[i]=a[i]-b[i];
}
c[i+b[0]]=x;
//进位
}
c[0]=a[0]+b[0];
int i=c[0];
while(c[i]==0&&i>1)i--; //删除前导0
for(int j=i;j>=1;j--)cout<<c[j];
return 0;
}
练习题:计算2的N次方
【题目描述】任意给定一个正整数N(N≤100),计算2的n次方的值。 【输入】输入一个正整数N。 【输出】输出2的N次方的值。 【输入样例】5 【输出样例】32
//对应位相减
i++;
}
c[0]=i;
while((c[i]==0)&&(i>1))i--; //最高位的0不输出
for(int j=i;j>=1;j--) cout<<c[j];
return 0;
}
【例3】高精度乘法。输入两个正整数,求它们的积。 【算法分析】
类似加法,可以用竖式求乘法。在做乘法运算时,同样
for(int i=1;i<=a[0];i++){
int x=0;
//用于存放进位
for(int j=1;j<=b[0];j++){
//对乘数的每一位进行处理
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;
(1)数据的接收方法和存贮方法 数据的接收和存贮:当输入的数很长时,可采用字符串方式输入,这
样可输入数字很长的数,利用字符串函数和操作运算,将每一位数取出, 存入数组中。另一种方法是直接用循环加数组方法输入数据。
char s[100]; cin>>s; len=strlen(s); for(int i=1;i<=len;i++) a[i]=s[len-i]-'0';
856 + 255 1111
图1
A3 A2 A1 + B3 B2 B1 C4 C3 C2 C1
图2
如果我们用数组A、B分别存储加数和被加数,用数组C存储结果。 则上例有A[1]=6,A[2]=5, A[3]=8,B[1]=5,B[2]=5,B[3]=2,C[4]=1, C[3]=1,C[2]=1,C[1]=1,两数相加如图2所示。
for(int i=1;i<=b[0];i++) b[i]=n2[b[0]-i]-'0'; //减数放入b数组
int i=1;
while(i<=a[0]||i<=b[0]){
if(a[i]<b[i]){
a[i]=a[i]+10;
//不够减,那么向高位借1当10
a[i+1]--;
}
c[i]=a[i]-b[i];
#include<iostream> #include<cstring> using namespace std; int main(){
char a1[101]; int n,a[10001]={0},b[10001]={0}; cin>>a1>>n; int l=strlen(a1); for(int i=0;i<=l-1;i++)a[i+1]=a1[i]-'0'; int x=0; //x是上次相除取得的余数 for(int i=1;i<=l;i++){
for(int i=1;i<=a[0];i++) a[i]=s[a[0]-i]-'0'; //将数串s转换为数组a,并倒序存储
} void add(int a[],int b[]){//a,b,c都为数组,分别存储被加数、加数、结果
int i=1,x=0; //x是进位
while((i<=a[0])||(i<=b[0])){ c[i]=a[i]+b[i]+x;//第i位相加并加上次的进位 x=c[i]/10;//向高位进位 c[i]=c[i]%10;//存储第i位的值 i++; //位置下标变量
【例4】高精除以低精。输入两个正整数,求它们的商和余数。
【算法分析】 做除法时,每一次上商的值都在0~9,每次求得的余数连接以后的若干位
得到新的被除数,继续做除法。因此,在做高精度除法时,要涉及到乘法运算和 减法运算,还有移位处理。当然,为了程序简洁,可以避免高精度除法,用0~9 次循环减法取代得到商的值。这里,我们讨论一下高精度数除以单精度数的结果, 采取的方法是按位相除法。
【高精度加法——常规写法】:
#include<iostream>
#include<cstring>
using namespace std;
int mai1[10001];
int a[10001]={0},b[10001]={0},c[10001]={0};
cin>>a1;
int i=1,x=0; while(i<=a[0]||i<=b[0]){
c[i]=a[i]+b[i]+x; //两数相加 x=c[i]/10; c[i]=c[i]%10; i++; } if(x>0)c[i]=x; //处理最高进位 else i--; while(c[i]==0&&i>1)i--; //最高位的0不输出 for(int j=i;j>=1;j--) cout<<c[j]; //输出结果 return 0; }
char a1[10001],b1[10001]; int a[10001]={0},b[10001]={0},c[10001]={0}; cin>>a1; cin>>b1; a[0]=strlen(a1);b[0]=strlen(b1); for(int i=1;i<=a[0];i++)a[i]=a1[a[0]-i]-'0'; for(int i=1;i<=b[0];i++)b[i]=b1[b[0]-i]-'0';
也有进位,同时对每一位进行乘法运算时,必须进行错位相加, 如图3、图4。
分析c数组下标的变化规律,可以写出如下关系式:ci = c’i +c”i +…由此可见,c i跟a[i]*b[j]乘积有关,跟上次的进位有关, 还跟原c i的值有关,分析下标规律,有c[i+j-1]= a[i]*b[j]+ x + c[i+j-1]; x=c[i+j-1]/10 ; c[i+j-1]%=10;
【例1】高精度加法。输入两个正整数,求它们的和。
【分析】 输入两个数到两个变量中,然后用赋值语句求它们的和,输出。但
是,我们知道,在C++语言中任何数据类型都有一定的表示范围。而当 两个被加数很大时,上述算法显然不能求出精确解,因此我们需要寻求 另外一种方法。在读小学时,我们做加法都采用竖式方法,如图1。 这 样,我们方便写出两个整数相加的算法。
//读入字符串s //用len计算字符串s的位数
//将数串s转换为数组a,并倒序存储
(2) 高精度数位数的确定 位数的确定:接收时往往是用字符串的,所以它的位数就
等于字符串的长度。
(3) 加法进位,借位处理 加法进位: int x=0,i=1; c[i]=a[i]+b[i]+x; c[i]=c[i]%10; x=c[i]/10;
cin>>b1; //输入加数与被加数
a[0]=strlen(a1);
b[0]=strlen(b1);
for(int i=1;i<=a[0];i++)a[i]=a1[a[0]-i]-'0';
//加数放入a数组
for(int i=1;i<=b[0];i++)b[i]=b1[b[0]-i]-'0'; //加数放入b数组
856 × 25 4280 1712 21400
图3
A3A2A1 × B2B1 C’4C’3 C’2 C’1 C”5C”4C”3C”2 C6C 5C4C 3C2C1
图4
高精度乘法的参考程序: #include<iostream> #include<cstring> using namespace std; int main(){
int t=x*10+a[i];//上次相除的余数要乘以十 ,加上当前这一位 b[i]=t/n;//相除取得商 x=t%n;//相除取得余数 }
int k=1; while(b[k]==0&&k<l)k++;//删除前面的0 for(int i=k;i<=l;i++){
cout<<b[i]; } cout<<endl; cout<<x; return 0; }
N进制加法(2<=N<=10)
输入一个正整数n,表明是n进制。然后输入两个n进制的数(, 当然数的每一位数字都不会超过n-1,并且加数的长度<=2000 位),求它们的和(用n进制表示) 样例输入:4
123 321 样例输出:1110
同类型挑战题:洛谷——B进制星球 https:///problemnew/show/P1604
【高精度加法——函数写法】:
#include<iostream> #include<cstring> using namespace std; void init(int a[]); void add(int a[],int b[]); int a[10001],b[10001],c[10001]; int main(){
2的n次方参考程序: int main(){
int n,a[10001]={0}; a[1]=1; int k=1; cin>>n; for(int i=1;i<=n;i++){
int x=0; for(int j=1;j<=k;j++){
int t=a[j]*2+x; x=t/10; a[j]=t%10; } if(x>0){ k++; a[k]=x; } } for(int i=k;i>=1;i--){ cout<<a[i]; } return 0; }
strcpy(n,n1); strcpy(n1,n2); strcpy(n2,n); cout<<"-"; //交换了减数和被减数,结果为负数 }
a[0]=strlen(n1);b[0]=strlen(n2);
for(int i=1;i<=a[0];i++) a[i]=n1[a[0]-i]-'0'; //被减数放入a数组
练习:除以13
【题目描述】 输入一个大于0的大整数N,长度不超过100位,要求输出其除以13得到的商和余数。 【输入】 一个大于0的大整数,长度不超过100位。 【输出】 两行,分别为整数除法得到的商和余数。
int a[10001]={0},b[10001]={0},c[10001]={0}; char n[10001],n1[10001],n2[10001]; cin>>n1; //输入被减数 cin>>n2; //输入减数 if (strlen(n1)<strlen(n2)||(strlen(n1)==strlen(n2)&&strcmp(n1,n2)<0)) //strcmp()为字符串比较函数,当n1==n2, 返回0; //n1>n2时,返回正整数;n1<n2时,返回负整数 { //处理被减数和减数,交换被减数和减数
第一章 高精度计算
利用计算机进行数值计算,有时会遇到这样的问题:有些计算要求精度高,希望计算 的数的位数可达几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的 限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高 精度计算。介绍常用的几种高精度计算的方法。
高精度计算中需要处理好以下几个问题:
init(a); init(b); add(a,b); for(int i=c[0];i>=1;i--)cout<<c[i]; return 0; }
void init(int a[]){ //传入一个数组
char s[10001]; cin>>s; //读入字符串s a[0]=strlen(s); //用a[0]计算字符串s的位数
}
if(x>0)c[i]=x; else i--; while(c[i]==0&&i>1)i--;//最高位的0不输出
c[0]=i;
}
【例2】高精度减法。输入两个正整数,求它们的差。
【算法分析】 类似加法,可以用竖式求减法。在做减法运算时,需要注意的是:被减数必须比减数大,同时需要处理借位。
减法借位:if (a[i]<b[i]) { --a[i+1]; a[i]+=10; } c[i]=a[i]-b[i];
}
c[i+b[0]]=x;
//进位
}
c[0]=a[0]+b[0];
int i=c[0];
while(c[i]==0&&i>1)i--; //删除前导0
for(int j=i;j>=1;j--)cout<<c[j];
return 0;
}
练习题:计算2的N次方
【题目描述】任意给定一个正整数N(N≤100),计算2的n次方的值。 【输入】输入一个正整数N。 【输出】输出2的N次方的值。 【输入样例】5 【输出样例】32
//对应位相减
i++;
}
c[0]=i;
while((c[i]==0)&&(i>1))i--; //最高位的0不输出
for(int j=i;j>=1;j--) cout<<c[j];
return 0;
}
【例3】高精度乘法。输入两个正整数,求它们的积。 【算法分析】
类似加法,可以用竖式求乘法。在做乘法运算时,同样
for(int i=1;i<=a[0];i++){
int x=0;
//用于存放进位
for(int j=1;j<=b[0];j++){
//对乘数的每一位进行处理
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;
(1)数据的接收方法和存贮方法 数据的接收和存贮:当输入的数很长时,可采用字符串方式输入,这
样可输入数字很长的数,利用字符串函数和操作运算,将每一位数取出, 存入数组中。另一种方法是直接用循环加数组方法输入数据。
char s[100]; cin>>s; len=strlen(s); for(int i=1;i<=len;i++) a[i]=s[len-i]-'0';
856 + 255 1111
图1
A3 A2 A1 + B3 B2 B1 C4 C3 C2 C1
图2
如果我们用数组A、B分别存储加数和被加数,用数组C存储结果。 则上例有A[1]=6,A[2]=5, A[3]=8,B[1]=5,B[2]=5,B[3]=2,C[4]=1, C[3]=1,C[2]=1,C[1]=1,两数相加如图2所示。
for(int i=1;i<=b[0];i++) b[i]=n2[b[0]-i]-'0'; //减数放入b数组
int i=1;
while(i<=a[0]||i<=b[0]){
if(a[i]<b[i]){
a[i]=a[i]+10;
//不够减,那么向高位借1当10
a[i+1]--;
}
c[i]=a[i]-b[i];
#include<iostream> #include<cstring> using namespace std; int main(){
char a1[101]; int n,a[10001]={0},b[10001]={0}; cin>>a1>>n; int l=strlen(a1); for(int i=0;i<=l-1;i++)a[i+1]=a1[i]-'0'; int x=0; //x是上次相除取得的余数 for(int i=1;i<=l;i++){
for(int i=1;i<=a[0];i++) a[i]=s[a[0]-i]-'0'; //将数串s转换为数组a,并倒序存储
} void add(int a[],int b[]){//a,b,c都为数组,分别存储被加数、加数、结果
int i=1,x=0; //x是进位
while((i<=a[0])||(i<=b[0])){ c[i]=a[i]+b[i]+x;//第i位相加并加上次的进位 x=c[i]/10;//向高位进位 c[i]=c[i]%10;//存储第i位的值 i++; //位置下标变量
【例4】高精除以低精。输入两个正整数,求它们的商和余数。
【算法分析】 做除法时,每一次上商的值都在0~9,每次求得的余数连接以后的若干位
得到新的被除数,继续做除法。因此,在做高精度除法时,要涉及到乘法运算和 减法运算,还有移位处理。当然,为了程序简洁,可以避免高精度除法,用0~9 次循环减法取代得到商的值。这里,我们讨论一下高精度数除以单精度数的结果, 采取的方法是按位相除法。
【高精度加法——常规写法】:
#include<iostream>
#include<cstring>
using namespace std;
int mai1[10001];
int a[10001]={0},b[10001]={0},c[10001]={0};
cin>>a1;
int i=1,x=0; while(i<=a[0]||i<=b[0]){
c[i]=a[i]+b[i]+x; //两数相加 x=c[i]/10; c[i]=c[i]%10; i++; } if(x>0)c[i]=x; //处理最高进位 else i--; while(c[i]==0&&i>1)i--; //最高位的0不输出 for(int j=i;j>=1;j--) cout<<c[j]; //输出结果 return 0; }
char a1[10001],b1[10001]; int a[10001]={0},b[10001]={0},c[10001]={0}; cin>>a1; cin>>b1; a[0]=strlen(a1);b[0]=strlen(b1); for(int i=1;i<=a[0];i++)a[i]=a1[a[0]-i]-'0'; for(int i=1;i<=b[0];i++)b[i]=b1[b[0]-i]-'0';
也有进位,同时对每一位进行乘法运算时,必须进行错位相加, 如图3、图4。
分析c数组下标的变化规律,可以写出如下关系式:ci = c’i +c”i +…由此可见,c i跟a[i]*b[j]乘积有关,跟上次的进位有关, 还跟原c i的值有关,分析下标规律,有c[i+j-1]= a[i]*b[j]+ x + c[i+j-1]; x=c[i+j-1]/10 ; c[i+j-1]%=10;
【例1】高精度加法。输入两个正整数,求它们的和。
【分析】 输入两个数到两个变量中,然后用赋值语句求它们的和,输出。但
是,我们知道,在C++语言中任何数据类型都有一定的表示范围。而当 两个被加数很大时,上述算法显然不能求出精确解,因此我们需要寻求 另外一种方法。在读小学时,我们做加法都采用竖式方法,如图1。 这 样,我们方便写出两个整数相加的算法。
//读入字符串s //用len计算字符串s的位数
//将数串s转换为数组a,并倒序存储
(2) 高精度数位数的确定 位数的确定:接收时往往是用字符串的,所以它的位数就
等于字符串的长度。
(3) 加法进位,借位处理 加法进位: int x=0,i=1; c[i]=a[i]+b[i]+x; c[i]=c[i]%10; x=c[i]/10;
cin>>b1; //输入加数与被加数
a[0]=strlen(a1);
b[0]=strlen(b1);
for(int i=1;i<=a[0];i++)a[i]=a1[a[0]-i]-'0';
//加数放入a数组
for(int i=1;i<=b[0];i++)b[i]=b1[b[0]-i]-'0'; //加数放入b数组
856 × 25 4280 1712 21400
图3
A3A2A1 × B2B1 C’4C’3 C’2 C’1 C”5C”4C”3C”2 C6C 5C4C 3C2C1
图4
高精度乘法的参考程序: #include<iostream> #include<cstring> using namespace std; int main(){
int t=x*10+a[i];//上次相除的余数要乘以十 ,加上当前这一位 b[i]=t/n;//相除取得商 x=t%n;//相除取得余数 }
int k=1; while(b[k]==0&&k<l)k++;//删除前面的0 for(int i=k;i<=l;i++){
cout<<b[i]; } cout<<endl; cout<<x; return 0; }
N进制加法(2<=N<=10)
输入一个正整数n,表明是n进制。然后输入两个n进制的数(, 当然数的每一位数字都不会超过n-1,并且加数的长度<=2000 位),求它们的和(用n进制表示) 样例输入:4
123 321 样例输出:1110
同类型挑战题:洛谷——B进制星球 https:///problemnew/show/P1604
【高精度加法——函数写法】:
#include<iostream> #include<cstring> using namespace std; void init(int a[]); void add(int a[],int b[]); int a[10001],b[10001],c[10001]; int main(){
2的n次方参考程序: int main(){
int n,a[10001]={0}; a[1]=1; int k=1; cin>>n; for(int i=1;i<=n;i++){
int x=0; for(int j=1;j<=k;j++){
int t=a[j]*2+x; x=t/10; a[j]=t%10; } if(x>0){ k++; a[k]=x; } } for(int i=k;i>=1;i--){ cout<<a[i]; } return 0; }
strcpy(n,n1); strcpy(n1,n2); strcpy(n2,n); cout<<"-"; //交换了减数和被减数,结果为负数 }
a[0]=strlen(n1);b[0]=strlen(n2);
for(int i=1;i<=a[0];i++) a[i]=n1[a[0]-i]-'0'; //被减数放入a数组
练习:除以13
【题目描述】 输入一个大于0的大整数N,长度不超过100位,要求输出其除以13得到的商和余数。 【输入】 一个大于0的大整数,长度不超过100位。 【输出】 两行,分别为整数除法得到的商和余数。