高精度算法
高精度算法
本文内容较多,信息量偏大,请仔细阅读。
1.高精度算法简介
高精度算法(High Accuracy Algorithm)是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘,开方等运算。对于非常庞大的数字无法在计算机中正常存储,于是,将这个数字拆开,拆成一位一位的,或者是四位四位的存储到一个数组中, 用一个数组去表示一个数字,这样这个数字就被称为是高精度数。高精度算法就是能处理高精度数各种运算的算法,但又因其特殊性,故从普通数的算法中分离,自成一家。
2.高精数读入
方法一:使用字符数组
#include<iostream> #include<cstdio> #include<cstring> using namespace std; char s[200]; int main(){ gets(s);//注,gets()在最新的c++里已经不能用了 cout<<strlen(s)<<endl<<s; return 0; } #include<iostream> #include<cstdio> #include<cstring> using namespace std; char s[200]; int main(){ cin>>s; cout<<strlen(s)<<endl<<s; return 0; } #include<iostream> #include<cstdio> #include<cstring> using namespace std; char s[200]; int main(){ scanf("%s",s); cout<<strlen(s)<<endl<<s; return 0; }
方法二:使用字符串
#include<iostream> #include<cstdio> #include<cstring> using namespace std; string s; int main(){ getline(cin,s); cout<<s.length()<<endl<<s; return 0; } #include<iostream> #include<cstdio> #include<cstring> using namespace std; string s; int main(){ cin>>s; cout<<s.length()<<endl<<s; return 0; }
3.高精数存储
s1="123456789"
a[0] | a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] |
---|---|---|---|---|---|---|---|---|
9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
s2="3456"
a[0] | a[1] | a[2] | a[3] |
---|---|---|---|
6 | 5 | 4 | 3 |
一般是倒着存(a[0]是个位,最后的元素是最高位)。
1、需要先计算个位,逆序存放方便对齐。
2、方便进位。
代码:
la=s.size();//用la存放字符串s的位数 for(i=0;i<la;i++)//将数串s转换为数组a,注意:倒序存储 a[i]=s[la-1-i] -'0';
4.高精加
进位
a[6] | a[5] | a[4] | a[3] | a[2] | a[1] | a[0] |
---|---|---|---|---|---|---|
+ | b[4] | b[3] | b[2] | b[1] | b[0] | |
c[6] | c[5] | c[4] | c[3] | c[2] | c[1] | c[0] |
加法法则:个位对齐,逢十进一。
代码实现
方法一:设置一个进位变量
if(la>lb) lc=la;//lc取最长位 else lc=lb; m=0; for(int i=0;i<lc;i++){ c[i]=(m+a[i]+b[i])%10; m=(m+a[i]+b[i])/10; } if(m>0){//最高位有进位时 c[lc]=m; lc++; }
方法二:先计算,最后处理进位
for(int i=0;i<lc;i++) c[i]=a[i]+b[i]; for(int i=0;i<lc;i++){ c[i+1]=c[i+1]+c[i]/10; c[i]=c[i]%10; } if(c[lc]>0) lc++;
a[3] | a[2] | a[1] | a[0] | |
---|---|---|---|---|
6 | 2 | 4 | 7 | |
+ | 3 | 7 | 9 | 5 |
9 | 9 | 13 | 12 | |
1 | 0 | 0 | 4 | 2 |
c[4] | c[3] | c[2] | c[1] | c[0] |
改进:去掉 数组
for(int i=0;i<la;i++) a[i]=a[i]+b[i]; for(int i=0;i<a;i++){ a[i+1]+=a[i]/10; a[i]%=10; } if(a[la]>0) la++;
代码
#include<iostream> #include<string> using namespace std; int main(){ int a[205]={0},b[205]={0}; string a1,b1; cin>>a1>>b1; int la=a1.length(),lb=b1.length(); for(int i=0;i<la;i++) a[i]=a1[la-1-i]-'0'; for(int i=0;i<lb;i++) b[i]=b1[lb-1-i]-'0'; if(lb>la) la=lb; for(int i=0;i<la;i++) a[i]+=b[i]; for(int i=0;i<la;i++){ a[i+1]+=a[i]/10; a[i]%=10; } if(a[la]>0) la++; while(la>0&&a[la-1]==0) la--;//删除前导零 for(int i=la-1;i>=0;i--) cout<<a[i]; return 0; }
5.高精减(跟高精加区别不大,所以不细说了)
借位
for(int i=0;i<la;i++){ if(a[i]<b[i]){ a[i+1]--;//跟一般的竖式思想一样,前一位减1 a[i]+=10;//本位加十 } a[i]-=b[i]; }
代码(不是最终版)
#include<iostream> #include<string> using namespace std; int main(){ int a[205]={0},b[205]={0}; string a1,b1; cin>>a1>>b1; int la=a1.length(),lb=b1.length(); if(a1==b1){ cout<<0; return 0; } for(int i=0;i<la;i++) a[i]=a1[la-1-i]-'0'; for(int i=0;i<lb;i++) b[i]=b1[lb-1-i]-'0'; for(int i=0;i<la;i++){ if(a[i]<b[i]){ a[i]+=10; a[i+1]-=1; } a[i]-=b[i]; } while(la>0&&a[la-1]==0) la--; for(int i=la-1;i>=0;i--) cout<<a[i]; return 0; }
但我们还可能遇到结果是负数的情况
所以,我们要在代码前面判断哪个数大。
如果第二个数大,那么我们就先输出负号,再让第二个数去减第一个数。
判断代码如下:
if(la<lb||la==lb&&a1<b1){ swap(a1,b1); swap(la,lb); cout<<"-"; }
在原始代码上加上判断代码即可
6.高精乘
高精乘单精
9 | 9 | 9 | ||
---|---|---|---|---|
* | 9 | 9 | ||
891 | 891 | 891 | ||
9 | 8 | 9 | 0 | 1 |
分析:
1.
2.再由低到高位依次处理进位;
3.最后处理最高位。
代码(高精乘单精)
#include<iostream> #include<string> using namespace std; int main(){ int la,b,m,a[260]={0}; string a1; cin>>a1>>b; la=a1.size(); for(int i=0;i<la;i++) a[i]=a1[la-i-1]-'0'; for(int i=0;i<la;i++) a[i]=a[i]*b; for(int i=0;i<la;i++){ a[i+1]=a[i+1]+a[i]/10; a[i]=a[i]%10; } m=a[la]; //最高位 while(m>0){ //可能有多次进位 a[la]=m%10; m/=10; ++la; } for(int i=la-1;i>=0;i--) cout<<a[i]; return 0; }
高精乘高精
分析:
假设乘数和被乘数的长度分别为
则最后的乘积长度最长为
下标关系:
a[2] | a[1] | a[0] | ||
---|---|---|---|---|
b[1] | b[0] | |||
a[2]*b[0] | a[1]*b[0] | a[0]*b[0] | ||
a[2]*b[1] | a[1]*b[1] | a[0]*b[1] | ||
c[4] | c[3] | c[2] | c[1] | c[0] |
代码(高精乘高精)
#include<iostream> #include<string> using namespace std; int main(){ int a[205]={0},b[205]={0},c[205]={0}; string a1,b1; cin>>a1>>b1; int la=a1.size(),lb=b1.size(),lc=la+lb; for(int i=0;i<la;i++) a[i]=a1[la-i-1]-'0'; for(int i=0;i<lb;i++) b[i]=b1[lb-i-1]-'0'; for(int i=0;i<la;i++) for(int j=0;j<lb;j++) c[i+j]+=a[i]*b[j]; for(int i=0;i<lc;i++){ c[i+1]+=c[i]/10; c[i]%=10; } while(lc>0&&c[lc-1]==0) lc--; for(int i=lc-1;i>=0;i--) cout<<c[i]; return 0; }
7.高精除
高精除以单精(与手工除类似)
#include<iostream> #include<string> using namespace std; int main(){ int a[205]={0},b,c[205]={0}; string a1; cin>>a1>>b; int la=a1.size(),lc=0,ys=0; for(int i=0;i<la;i++) a[i]=a1[i]-'0'; for(int i=0;i<la;i++){ c[i]=(ys*10+a[i])/b; ys=(ys*10+a[i])%b; } while(c[lc]==0&&lc<la-1) lc++; for(int i=lc;i<la;i++) cout<<c[i]; return 0; }
高精除以高精
大体思路:
高精度除法,这个和加减乘一样,我们都要从手算的角度入手。举 一个例子,比如
第一位
将
把
将
终止程序。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)