高精度入门(神犇请绕道)
2026-07-24 10:00:05
发布于:北京
神犇请请来此
蒟蒻们好,今天我来讲高精度了。
为什么要有高精度
首先你们平时做运算是不是这样:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,b;
cin>>a>>b;
cout<<a+b<<" "<<a-b<<" "<<a*b<<" "<<a/b<<" "<<a%b;
return 0;
}
如果你们这样做,可以试一下这道题,如果你用C里的整数运算,只能拿到部分(40)分,为什么会这样?
原来,C中编译器对整数的运算的支持最高到long long(64位,约为十进制1e18),部分编译器可以做到int128(128位,约为十进制1e39,需手动定义且不能输入输出),而有些题目的数据比1e39还大,这时就需要高精度了。
高精度模板
高精度的实现方式类似于我们小学学过的竖式,一位一位的加,遇到大于十的情况就进位,比较主流的方式是用C++的string(不会的可以自学一下字符串)。
你们最喜欢的代码来啦!
#include<bits/stdc++.h>
using namespace std;
int a[1005],b[1005],c[1005];
int main()
{
string as,bs;
cin>>as>>bs;
reverse(as.begin(),as.end());//这里的reverse是反转函数,作用是将字符串反转,这里之所以要反转是因为要模拟竖式;如123和45,第一个字符串下标0是1,但45与123的位数不同,所以导致了5与3的下标不同,无法进行加减,反转后就不会有这个问题
reverse(bs.begin(),bs.end());
for(int i=0;i<as.size();i++)
{
a[i]=as[i]-'0';//把字符变成数字(这里亦可减48),自行了解ASCII码
}
for(int i=0;i<bs.size();i++)
{
b[i]=bs[i]-'0';
}
for(int i=0;i<=1000;i++)
{
c[i]=a[i]+b[i];//数组模拟竖式加法
}
for(int i=0;i<=1000;i++)
{
if(c[i]>=10)//如果大于十了就进位
{
c[i+1]++;
c[i]-=10;
}
}
int s=1000;//这里位数最多到500,我做的加强版位数到一千
while(c[s]==0&&s>0)
{
s--;//防止输出前导零
}
for(int i=s;i>=0;i--)
{
cout<<c[i];//倒序输出结果
}
return 0;
}
同样的道理, 我们也可以做出乘法的高精度:
高精度乘高精度:
#include<bits/stdc++.h>
using namespace std;
int a[1000005],b[1000005],c[1000005];
int main()
{
string as,bs;
cin>>as>>bs;
reverse(as.begin(),as.end());//前面讲过了,这里就不再赘述
reverse(bs.begin(),bs.end());
for(int i=0;i<as.size();i++)
{
a[i]=as[i]-'0';
}
for(int i=0;i<bs.size();i++)
{
b[i]=bs[i]-'0';
}
for(int i=0;i<as.size();i++)
{
for(int j=0;j<=bs.size();j++)
{
c[i+j]+=a[i]*b[j];//模拟竖式
}
}
for(int i=0;i<=3000;i++)
{
if(c[i]>=10)//如果大于十了就进位
{
c[i+1]+=c[i]/10;//这里用+=是因为有时乘法不止进一位
c[i]%=10;
}
}
int s=30000;
while(c[s]==0&&s>0)
{
s--;
}
for(int i=s;i>=0;i--)
{
cout<<c[i];
}
return 0;
}
高精度乘低精度:
#include<bits/stdc++.h>
using namespace std;
int a[3005],c[3005];
int main()
{
string as;
cin>>as;
int b;//因为数值不大,用int就能存下
cin>>b;
reverse(as.begin(),as.end());
for(int i=0;i<as.size();i++)
{
a[i]=as[i]-'0';
}
for(int i=0;i<=3000;i++)
{
c[i]=b*a[i];//模拟竖式
}
for(int i=0;i<=3000;i++)
{
if(c[i]>=10)
{
c[i+1]+=c[i]/10;
c[i]%=10;
}
}
int s=3000;
while(c[s]==0&&s>0)
{
s--;
}
for(int i=s;i>=0;i--)
{
cout<<c[i];
}
return 0;
}
减法:
#include <bits/stdc++.h>
using namespace std;
int a[10010],b[10010],c[10010];
string s1,s2;
bool cmp(string s1,string s2)
{
if(s1.size()!=s2.size()) return s1.size()<s2.size();//这么做是防止小于零溢出
else return s1<s2;
}
int main()
{
cin >> s1 >> s2;
if(cmp(s1,s2))
{
cout << "-";//如果第一个比第二个小就输出负号
swap(s1,s2);
}
int len = max(s1.size(),s2.size()) -1;//最大下标
int l1 = s1.size()-1;
int l2 = s2.size()-1;
for(int i=0;i<=l1;i++) a[i] = s1[l1-i] - '0';
for(int i=0;i<=l2;i++) b[i] = s2[l2-i] - '0';
for(int i=0;i<=len;i++){
c[i] += a[i]-b[i];
if(c[i]<0)// 借一当十
{
c[i] += 10;
c[i+1] -= 1;
}
}
while(len>0&&c[len]==0) len--;
for(int i=len;i>=0;i--) cout << c[i];
return 0;
}
高精度除法:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
const int T = 1e5+5;
int na[T], nb[T];
bool check(string a, string b);//先声明后定义
string sub(string a, string b);
int main(){
string a, b;
cin >> a >> b;
int lena = a.size(), lenb = b.size();
string q, r;
for (int i = 0; i < lena; i++){
r.push_back(a[i]);//字符串操作,将一个符号 从尾部放入string
int idx = 0;
while(idx < r.size()-1 && r[idx] == '0') idx++;
r = r.substr(idx);//去前导0,substr截取字串
int cnt = 0;
while(check(r, b)){
r = sub(r, b);
cnt++;
}
q += cnt + '0';
}
//去商的前导0
int i = 0, lenq = q.size();
while(i < lenq-1 && q[i] == '0') i++;
//输出商和余数
for(; i < lenq; i++) cout << q[i];
cout << endl;
int lenr = r.size();
for (int i = 0; i < lenr; i++) cout << r[i];
return 0;
}//此题需输出商和余数,需要求商或余数的请自行截取
bool check(string a, string b){
int lenb = b.size();
if(a.size() != b.size()) return a.size() > b.size();
else{
for (int i = 0; i < lenb; i++){
if(a[i] != b[i]) return a[i] > b[i];
}
}
return true;
}
string sub(string a, string b){
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
int lena = a.size();
string c;
int t = 0;
for (int i = 0; i < lena; i++){
char bi = (i < b.size()) ? b[i] : '0';//三目运算符,不会的自行学习
int x = a[i] - bi - t;
if(x < 0){
x += 10;
t = 1;
}else t = 0;
c += x + '0';
}
int lenc = c.size();
while(lenc > 1 && c[lenc-1] == '0') lenc--;
c = c.substr(0, lenc);
reverse(c.begin(), c.end());
return c;
}
例题
附加题一
附加题二
附加题三
神犇题(蒟蒻误入)
不要脸的求点赞和关注
版权声明:一些信息出自此帖。
(转载自本人洛谷账号,链接全是洛谷的)
下次我还是写卡特兰数吧(逃)
全部评论 1
因ACGO中markdown的一些问题,导致一些字符显示不出来,更好的阅读体验
2026-07-24 来自 北京
0



















有帮助,赞一个