关于高精度
高精度算法
高精度算法,是指参与运算的数(加法,减法,因数......),而这些数字的巨大,远远超过了unsigned long long
或其他标准数据类型,这时,我们就要用高精度算法了…… 不得不说,极其毒瘤啊
众所周知,一般的高精度算法都是模拟竖式,这显然是对的,但为什么是这样呢?首先,我们知道,2020以前的大部分电脑都是很……很聪明,它只听你说对的话,如果你说错了话,他就反了你了……
高精度起源于很久很久以前,也不知道为什么,可能是因为人发明的方法更聪明些,就被计算机采用了……
高精度加法[1]
- 我们在一开始时需要把两个字符串右移,以求右对齐,来进行模拟。
- 左移是在充分必要时才用的。[2]
- 在模拟时,我们可以再模拟的时候就直接进位,也可以把进位的位保存下来,到了最后再加,这里编者用的前者。
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1005
char s1[MAXN], s2[MAXN], ans[MAXN];
inline void right_move(char *s) //这里用的是指针,也可以用void right_move(char s[])来定义,效果一样
{
int len = strlen(s);
for(register int i = len - 1, j = MAXN - 1; i >= 0; i--, j--)
{
s[j]=s[i]-48;
s[i]=0;
}
}// 右移函数,作用是向右对齐
inline void left_move(char *s)
{
int i = 0;
while(s[i] == 0)
i++;
for(int j = 0; i < MAXN;)
{
s[j++] = s[i++] + 48;
s[i-1] = 0;
}
}// 左移函数,作用是向左对齐
void add(char *s1,char *s2,char *ans)
{
memset(ans,0,sizeof ans);
int len1=strlen(s1),len2=strlen(s2);
int len=len1>len2?len1:len2;
right_move(s1);
right_move(s2);// 这里两行我们进行向右对齐,以便模拟
for(int i=MAXN-1;i>=MAXN-len;i--)
{
ans[i]+=s1[i]+s2[i]; // 这里进行'+'的操作
ans[i-1]=ans[i]/10; //进位
ans[i]=ans[i]%10;
}
left_move(ans);
}
int main()
{
scanf("%s%s",s1,s2);
add(s1,s2,ans);
printf("%s",ans);
}
高精度减法[3]
- 和加法一样,我们需要以字符串来读入。
- 首先要比较被减数和减数的大小,如果被
减数小于减数,我们应该拿减数来减去被
减数,并在结果前加‘-’。 - 考虑大小的时候优先考虑长度,若长度相等,则可以作为字符串直接比
较大小。 - 比较大小后,拿大的减小的,如高精加,用加法模拟。
- 先将两个数右对齐,然后,逐位做减法,
减法要考虑借位,如果某一位不够减,则
向它左边借位。
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1005
char s1[MAXN], s2[MAXN], ans[MAXN];
inline void right_move(char *s) //右移
{
int len = strlen(s);
for(register int i = len - 1, j = MAXN - 1; i >= 0; i--, j--)
{
s[j]=s[i]-48;
s[i]=0;
}
}
inline void left_move(char *s) //左移
{
int i = 0;
while(s[i] == 0)
i++;
for(int j = 0; i < MAXN;)
{
s[j++] = s[i++] + 48;
s[i-1] = 0;
}
}
inline int cmp(char *s1, char *s2) //这个是比较两个字符串大小的函数
{
int len1 = strlen(s1), len2 = strlen(s2);
if(len1 > len2)
return 1;
else if(len1 < len2)
return -1;
else
return strcmp(s1, s2);
}
void sub(char *s1,char *s2,char *ans) //这个显然就是高精减♂啦~
{
memset(ans,0,sizeof ans);
int len1 = strlen(s1), len2 = strlen(s2);
int len = len1 > len2 ? len1 : len2;
right_move(s1);
right_move(s2);
for(register int i = MAXN - 1; i >= MAXN - len; i--)
{
ans[i] += s1[i] - s2[i];
if(ans[i] < 0)
{
ans[i - 1]--;
ans[i] += 10;
}
}
left_move(ans);
return ;
}
int main()
{
scanf("%s%s",s1,s2);
if(cmp(s1,s2)>0)
{
sub(s1,s2,ans);
printf("%s",ans);
}
else if(cmp(s1,s2)<0)
{
sub(s2,s1,ans);
printf("-%s",ans);
}
else
printf("0");
}
高精度乘法[4]
同样有几个点需要注意:
- 还是用字符串输入
- 最后
ans
数组的长度应为a+b
位才不会出问题。 - 采用左对齐更方便
Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000005
char num1[maxn], num2[maxn], res[maxn];
void multi(char *s1, char *s2, char *s3)
{
int len1 = strlen(s1), len2 = strlen(s2);
for(register int i = 0; i < len1; i++)
{
for(register int j = 0; j < len2; j++)
s3[i + j + 1] += (s1[i] - 48) * (s2[j] - 48);
for(register int k = len1 + len2 - 1; k > 0; k--)
{
s3[k - 1] += s3[k] / 10;
s3[k] = s3[k] % 10;
}
}
return ;
}
int main()
{
scanf("%s",num1);
scanf("%s",num2);
int len1 = strlen(num1), len2 = strlen(num2);
multi(num1, num2, res);
int i = 0;
while(res[i] == 0 && i < len1 + len2)
i++;
if(i == len1 + len2)
printf("0"); //结果为0的情况
else
{
for(; i < strlen(num1) + strlen(num2); i++)
printf("%c", res[i] + 48);
}
return 0;
}
高精度除法[5]
- 还是模拟竖式除法
- 我们不好估算商是多少,可以换成减法,
不断的减去除数。
#include <bits/stdc++.h>
using namespace std;
#define MAXN 2005
char num1[MAXN], num2[MAXN], res[MAXN];
int i,j,k,len1, len2, d = 0;
int mycmp(char *s1,char *s2,int start,int end)
if(end - start + 1 > len2)
return 1;
else if(end - start + 1 < len2)
return -1;
else
return strncmp(s1 + start, s2, len2);
}
int main()
{
scanf("%s",num1);
scanf("%s",num2);
len1 = strlen(num1), len2 = strlen(num2);
int start = 0, end = len2;
while(1)
{
end = start + len2 - 1;
while(end < len1 && mycmp(num1, num2, start, end) < 0)
end++;//不够除时,end往后移
if(end >= len1)
break;
while(mycmp(num1, num2, start, end) >= 0)
{
for(i=len2-1,j=end;i>=0;i--,j--)
{
if(num1[j]<num2[i])
{
num1[j]+=10;
num1[j-1]--;
}
num1[j]=num1[j]-num2[i]+48;//用减法来做除法
}
res[end]++;//减一次,该位的商增加1
while(start < len1 && num1[start] == '0')
start++;//被除数前面的0跳过
}
}
当然 是惯例,在最后 肯定会有一个菜单:一个封装了简单高精度的结构体
好东西模板
#include <bits/stdc++.h>
using namespace std;
#define Max(a,b) ((a)>(b)?(a):(b))
#define LL long long
struct bignum
{
LL a[2000],lim;
int len;
bignum(){
memset(a, 0, sizeof(a));
len = 1; lim = 100000000LL;
}
bool operator<(const bignum &b) const
{
if(len < b.len)
return 1;
if(len > b.len)
return 0;
for(register int i = len; i >= 1; --i)
{
if(a[i] < b.a[i])
return 1;
if(a[i] > b.a[i])
return 0;
}
return 0;
}
void operator+=(const bignum &b)
{
len = Max(len, b.len);
for(register int i = 1; i <= len; ++i)
a[i] += b.a[i];
for(register int i = 1; i <= len; ++i)
{
a[i + 1] += a[i] / lim;
if(i == len && a[i + 1])
++len;
a[i] %= lim;
}
}
bignum operator + (const bignum &b) const
{
bignum c = *this;
c += b;
return c;
}
void operator -= (const bignum &b)
{
for(register int i = 1; i <= len; ++i)
{
a[i] -= b.a[i];
if(a[i]<0)
a[i] += lim, --a[i+1];
}
for(; len>1 && !a[len]; --len);
}
bignum operator-(const bignum &b) const
{
bignum c = *this;
c -= b;
return c;
}
void operator*=(LL b)
{
for(register int i=1;i<=len;++i)
a[i] *= b;
for(int i=1;i<=len;++i){
a[i+1]+=a[i]/lim;
if(i==len && a[i+1]) ++len;
a[i]%=lim;
}
}
bignum operator*(LL b) const
{
bignum c=*this; c*=b;
return c;
}
void operator*=(const bignum &b)
{
bignum c; c.len=len+b.len-1;
for(LL i=1;i<=len;++i)
for(LL j=1;j<=b.len;++j)
c.a[i+j-1]+=a[i]*b.a[j];
for(LL i=1;i<=c.len;++i){
c.a[i+1]+=c.a[i]/lim;
if(i==c.len && c.a[i+1]) ++c.len;
c.a[i]%=lim;
}
*this=c;
}
bignum operator*(const bignum &b) const
{
bignum c=*this; c*=b;
return c;
}
void operator/=(LL b)
{
for(LL i=len;i>1;--i){
a[i-1]+=a[i]%b*lim;
a[i]/=b;
}
for(a[1]/=b;len>1 && !a[len];--len);
}
bignum operator/(const LL &b) const
{
bignum c=*this; c/=b;
return c;
}
void operator/=(const bignum &b)
{
LL i,j,l,r,mid;
bignum c, _b , res;
if (*this<b) {
*this=res;
return;
}
res.len = len-b.len+1;
for(i = res.len; _b=b,l=0,r=lim,i>=1; --i){
for(j=1; j < i; ++j) _b*=lim;
while(l<r){
mid=(l+r+1)>>1;
c = _b*mid;
if(*this<c) r=mid-1;
else l=mid;
}
*this-=_b*l; res.a[i]=l;
}
for(*this=res;len>1 && !a[len];--len);
}
bignum operator/(const bignum &b) const
{
bignum c=*this; c/=b;
return c;
}
void Read(char *s)
{
len=strlen(s);
for (LL i=0,j;j=(len-i-1)/8+1,i<len;i++)
a[j]=a[j]*10+s[i]-'0';
if (len%8) len=len/8+1;
else len/=8;
}
void Print()
{
printf("%I64d",a[len]);
for(LL i=len-1;i>=1;i--)
printf("%08I64d",a[i]);
printf("\n");
}
};
int main()
{
return 0;
}
高精度第一阶的算法笔记,请大家点下赞,在评论区指出错误QAQ