算法初步入门—简单数学之高精度整数运算
前言: 作为一个蒟蒻,才刚刷题刷到高精度运算,花了半天的时间去理解消化并实践了下这点儿刚学的知识,而晚上打牌又连跪二十把,于是化悲愤为力量,写篇文章来梳理下白天学到的东西(现在才明白知识结构化的重要,会不会太晚,汗颜),第一次写博客,希望各路巨佬可以多多指教,不足之处很多,多多见谅。
高精度整数简介
那么,我们先来了解下什么是高精度整数。
高精度整数,听起来好像什么很高大上的东东,but,它其实也有另一个土名----大整数。
以我们c++中基本的数据类型来说,int型的数据范围才为 -2147483648~2147483647([−2^31, 2^31−1]),而long long的数据范围为-9223372036854775808~9223372036854775807([−2^63, 2^63−1]),其实对于大多数情况,这些数据范围已经够用了,
but,我们现在也算是大数据时代,对于一些情况这些基本数据类型不足以存放我们的大整数,那该怎么办了,不急,我们一步一步来介绍。
高精度整数的存储
高精度整数的存储很简单,可以用我们最常用的数组,用数组来存放我们的高精度整数的每一位,即整数的高位存储在数组的高位,整数的低位存储在数组的低位。在具体应用中,为了方便随时调取高精度整数长度,我们一般会开一个结构体:
struct bign{
int d[10000]; //存放高精度整数的数组,暂开10000个空间,视具体情况而定
int len; //高精度整数长度
bign()
{
len=0;
fill(d,d+10000,0); //将数组所有元素初始化为0
//memset(d,0,sizeof(d));也是可以的
}
};
而输入高精度整数时,我们一般先用字符串读入,在把字符串另存为至bign结构体,给予bign结构体一个也相当于初始化的过程:
//初始化,将接收输入的str数组反转,逆向保存至bign结构体中,
//高精度元素低位存至结构体低位,依次后推
//因为接收输入的字符串数组中,高精度整数的高位存在字符数组低位,
//所以存到bign结构体时需要反转
bign init(char str[])
{
bign a;
a.len=strlen(str); //两种数组的长度相同
for(int i=0;i<a.len;i++)
{
a.d[i]=str[a.len-1-i]-'0'; //将str数组逆序赋值给结构体bign中的数组
}
return a;
}
高精度整数的四则运算
这四则运算说实话没有什么逻辑难度,其实就是模拟我们小学学习的加减乘除过程,都是四则运算的基本原理,只不过是用程序来把过程造出来罢了。
高精度整数加法
举个简单例子
89+21
先从最小位相加
9+1=10
对10余数为0,和的个位a[0]=0,十位进10/10=1,
8+2+1=11
对10余数为1,和的十位a[1]=1,百位进11/10=1,
0+1=1
a[2]=1;结束
a[0 ~ 2]=0,1,1; a[2~1]=1,1,0;
89+21=110;
bign add(bign a,bign b)
{
bign c; //开一个c来存放相加完的数组
int len;
if(a.len>=b.len) //选择最长的数组来作为接下来相加循环的最大值
len=a.len;
else
len=b.len;
int carry=0; //代表进位数
for(int i=0;i<len;i++)
{
int t=carry+a.d[i]+b.d[i];
if(t>=10) carry=t/10; //更新进位数
c.d[i]=t%10;
}
if(carry!=0) //判断两数相加是否得到更高的位数
{ //若有,则开辟更高的数组来存放最高位
c.d[len]=carry;
c.len=len+1;
}
else
{
c.len=len;
}
return c;
}
高精度整数减法
原理同加法,也是模拟我们普通的减法过程
bign sub(bign a,bign b)
{
bign c;
int len;
if(a.len>=b.len)
len=a.len;
else
len=b.len;
for(int i=0;i<len;i++)
{
if(a.d[i]<b.d[i])
{
a.d[i+1]--; //若相同位数被减数小于减数,则向高位借1
c.d[i]=a.d[i]+10-b.d[i]; //同时借的1,由于高一位,所以 ×10 加到被减数
}
else
{
c.d[i]=a.d[i]-b.d[i];
}
}
c.len=len;
while(c.len-1>=1&&c.d[c.len-1]==0) //因为减法所得数位数范围为1-len,所以直接循环判断
{
c.len--;
}
return c;
}
高精度整数乘法(高精度乘低精度)
举个栗子
12*12=124
+0 1 2
×0 1 2
+0 2 4
+1 2 0
+1 4 4
bign multiply(bign a,int b) //高精度数乘低精度
{ //(能用基本数据类型存储的数据,本代码以int型展开)
bign c;
int carry=0;
for(int i=0;i<a.len;i++)
{
int t;
t=carry+a.d[i]*b;
carry=t/10;
c.d[i]=t%10;
}
c.len=a.len;
while(carry!=0) //和减法一样,相乘结果进位数不确定有几位,可能不止一位,while循环
{
c.d[c.len++]=carry%10;
carry/=10;
}
return c;
}
高精度整数除法(高精度除以低精度)
还是正常的模拟除以过程啦,可以边看代码边在草稿纸上自己计算一下啦,过程很重要。
bign divide(bign a,int b)
{
bign c;
int len=a.len;
int carry=0;
for(int i=len-1;i>=0;i--)
{
int t=carry*10+a.d[i]; //暂存
if(t>=b)
{
c.d[i]=t/b; //模拟我们正常的除法计算
carry=t%b; //余数就交给我们低一位数,如此循环
}
else
{
c.d[i]=0;
carry=t;
}
}
c.len=a.len;
while(c.d[c.len-1]==0&&c.len-1>0)
{
c.len--;
}
return c;
}
程序就是一个动手玩儿的过程,脑过千遍不如手过一遍,望大家一起加油,努力进步,如果有什么错误请私信我,毕竟是小蒟蒻。
参考书籍:《算法笔记》