高精度的定义
什么是高精度?
高精度运算是指在计算机编程或数学计算中,处理超出标准数据类型范围的技术。通常用于需要几十位甚至上千位有效数字的场景
为什么不能直接用正常数据类型运算呢?
下面给出一些数据类型的存储范围:
int:
−
2
31
-2^{31}
−231~
2
31
−
1
2^{31}-1
231−1
long long:
−
2
63
-2^{63}
−263~
2
63
−
1
2^{63}-1
263−1
unsigned long long:
0
0
0~
2
64
−
1
2^{64}-1
264−1
这些数据类型的存储范围无法满足我们的巨大数据
这时候,有2种选择,
- 用高精度
- 用int128_
先讲int128_
int128_就是类似于利用读写模板改造成的小型高精度
那他的范围有多大呢?
给个具体数据
i
n
t
:
−
2
,
147
,
483
,
648
int:-2,147,483,648
int:−2,147,483,648~
2
,
147
,
483
,
647
2,147,483,647
2,147,483,647
(
(
(±
10
位
)
10位)
10位)
l o n g long long l o n g : − 9 , 223 , 372 , 036 , 854 , 775 , 808 long:-9,223,372,036,854,775,808 long:−9,223,372,036,854,775,808~ 9 , 223 , 372 , 036 , 854 , 775 , 807 9,223,372,036,854,775,807 9,223,372,036,854,775,807 ( ( (± 19 位 ) 19位) 19位)
u
n
s
i
g
n
e
d
unsigned
unsigned
l
o
n
g
long
long
l
o
n
g
:
long:
long:
0
0
0~
18
,
446
,
744
,
073
,
709
,
551
,
615
18,446,744,073,709,551,615
18,446,744,073,709,551,615
(
(
(+
20
位
)
20位)
20位)
i
n
t
128
int128
int128_
:
:
:
−
2
127
-2^{127}
−2127到
2
127
−
1
2^{127}-1
2127−1,即
− 170141183460469231731687303715884105728 -170141183460469231731687303715884105728 −170141183460469231731687303715884105728~ 170141183460469231731687303715884105727 170141183460469231731687303715884105727 170141183460469231731687303715884105727
(
(
(±
39
位
)
39位)
39位),很大的范围,但是不如高精,只能满足部分数据
用这个就是图个方便,下面上代码
int128_模板
#include <bits/stdc++.h>
using namespace std;
inline __int128 read(){
__int128 x=0;
short f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
inline void print(__int128 x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
print(x/10);
putchar(x%10+'0');
}
int main(){
__int128 a=read();
__int128 b=read();
print(a+b);
cout <<endl;
return 0;
}
OK继续正文:高精度
回到刚刚2选1的选择,如果我们选了1,那么
高精度可以处理几千位的运算,但是代码要更复杂一些
不像int128_,高精度的运算需要把
+
−
×
÷
+-×÷
+−×÷分开写函数
高精度的原理
原理就是用
s
t
r
i
n
g
string
string(字符串)或者
c
h
a
r
char
char数组代替int等数据类型
在输入时就用
s
t
r
i
n
g
string
string(字符串)或者
c
h
a
r
char
char数组存储
- 如果是加法:模拟手工加法,逐位相加并处理进位
- 如果是减法:先确保 a − b a-b a−b( a ≥ b a≥b a≥b),再逐位相减并处理借位
- 如果是乘法:模拟手工乘法,逐位相乘后累加
- 如果是除法:模拟手工除法,逐位试商,从高位到低位处理
加法模板
int a[10001],b[10001],c[10001];
string add(string a1,string b1){
int lena=a1.size();
int lenb=b1.size();
for(int i=0;i<lena;i++){
a[i]=a1[lena-1-i]-'0';
}
for(int i=0;i<lenb;i++){
b[i]=b1[lenb-1-i]-'0';
}
int lenc=max(lena,lenb),t=0;
for(int i=0;i<lenc;i++){
c[i]=a[i]+b[i]+t;
if(c[i]>=10){
t=1;
c[i]%=10;
}else{
t=0;
}
}
if(t==1){
lenc++;
c[lenc-1]=1;
}
string s;
for(int i=lenc-1;i>=0;i--){
s+=c[i]+'0';
}
return s;
}//输入两个相加的数的字符串即可返回结果
减法模板
int a[10001],b[10001],c[10001];
bool cmp(string s1,string s2){
if(s1.size()<s2.size())
return true;
else if(s1.size()>s2.size())
return false;
else{
if(s1<s2)
return true;
return false;
}
}
string sub(string a1,string b1){
if(cmp(a1,b1)){
putchar('-');
swap(a1,b1);
}
int lena=a1.size();
int lenb=b1.size();
for(int i=0;i<lena;i++){
a[i]=a1[lena-1-i]-'0';
}
for(int i=0;i<lenb;i++){
b[i]=b1[lenb-1-i]-'0';
}
int lenc=lena;
for(int i=0;i<lenc;i++){
if(a[i]<b[i])
{
a[i+1]--;
a[i]+=10;
}
c[i]=a[i]-b[i];
}
while(lenc>=1&&c[lenc-1]==0){
lenc--;
}
string s;
for(int i=lenc-1;i>=0;i--){
s+=c[i]+'0';
}
return s;
}//输入两个字符串即可返回相减的结果
乘法模板
int a[10001],b[10001],c[10001];
string mul(string a1,string b1){
int lena=a1.size();
int lenb=b1.size();
int lenc=lena+lenb;
for(int i=0;i<lena;i++){
a[i]=a1[lena-i-1]-'0';
}
for(int i=0;i<lenb;i++){
b[lenb-i-1]=b1[i]-'0';
}
for(int i=0;i<lena;i++){
for(int j=0;j<lenb;j++)
{
c[i+j]+=a[i]*b[j];
if(c[i+j]>=10)
{
c[i+j+1]+=c[i+j]/10;
c[i+j]%=10;
}
}
}
while(lenc>1&&c[lenc-1]==0){
lenc--;
}
string s;
for(int i=lenc-1;i>=0;i--){
s+=c[i]+'0';
}
return s;
}//输入两个字符串即可返回相乘结果
除法模板
高精除以低精 无余数
int a[10001],c[10001];
string div(string a1,int b){
int lena=a1.size();
for(int i=0;i<lena;i++){
a[i]=a1[i]-'0';
}
long long r=0,cnt=0;
for(int i=0;i<lena;i++){
r=r*10+a[i];
cnt++;
c[cnt]=0;
if(r>=b)
{
c[cnt]=r/b;
r%=b;
}
}
int i=0;
while(c[i]==0&&(cnt-i)>0){
i++;
}
string s;
for(;i<=cnt;i++){
s+=c[i]+'0';
}
return s;
}
高精除以低精 带余数(注意函数是 void \text{void} void )
int a[10001],c[10001];
void div(string a1,int b){
int lena=a1.size();
for(int i=0;i<lena;i++){
a[i]=a1[i]-'0';
}
long long r=0,cnt=0;
for(int i=0;i<lena;i++){
r=r*10+a[i];
cnt++;
c[cnt]=0;
if(r>=b)
{
c[cnt]=r/b;
r%=b;
}
}
int i=0;
while(c[i]==0&&(cnt-i)>0){
i++;
}
for(;i<=cnt;i++){
cout<<c[i];
}
cout<<endl<<r<<endl;
}//c是商,r是余数
例题
例题来源于
洛谷
洛谷
洛谷(例题太多了,不在这里展示)
例题
1
例题1
例题1←高精度加法
例题
2
例题2
例题2←高精度减法
例题
3
例题3
例题3←高精度乘法
例题
4
例题4
例题4←高精度除法
补充&优化
- 压位储存
使用10000或更高进制减少计算次数 - FFT加速乘法
对于超大数乘法,可使用快速傅里叶变换(FFT)复杂度从 O ( n 2 ) O(n^2) O(n2)降至 O ( n log n ) O(n \log n) O(nlogn) - 预处理与缓存
频繁使用的运算结果可预先计算并缓存(如阶乘表)
高精度的应用场景
- 大数阶乘:
计算 1000 ! 1000! 1000!等超出long long范围的结果 - 高精度幂运算:
如 2 1000 2^{1000} 21000的精确值 - 数论问题
大素数判定、模运算等
~ 完结撒花 完结撒花 完结撒花 ~
附:Python语言不需要高精qwq,Py自带高精~
推荐
洛谷
洛谷
洛谷作为你的刷题区域
下一篇预告:你猜


770

被折叠的 条评论
为什么被折叠?



