由于整型数的位数有限,因此整型数不能满足大整数(超长整数)的运算要求 。大整数计算是利用字符串来表示大整数,即用字符串的一位字符表示大整数的一位数值,然后根据四则运算规则实现大整数的四则运算。
大数的结构
typedef struct bigint
{
char *num; //指向长整数数组(序号0中保存着最高位)
char sign; //符号(1表示正数,-1表示负数)
int digit; //保存该数的位数(实际位数)
}BIGINT, *pBIGINT;
加法运算
执行加法之前,先判断两数是同号相加还是异号相加,同号则执行加法运算,异号则执行减法运算。在加法运算中,首先将被操作的两个数对齐,然后从低位向高位逐渐相加,在对应位置相加时,要考虑是否有地位相加的进位。
实现代码:
首先将被加数中的内容复制到结果数组中,然后从低位逐渐加到结果中去,最后判断加数各位加完之后是否还有进位,如果有则要累加到高位中去。BigintTirm()用于整理大数,去掉前多余的0,并调整其位数
void BigIntAdd(pBIGINT num1,pBIGINT num2,pBIGINT result)
{
int i,carry;
carry=0; //清除进位
result->sign =num1->sign; //保存符号
//将被加数复制到结果数组中
for(i=0;idigit;i++)
result->num[i]=num1->num[i];
//num2中的数小,可能位数也少些
for(i=0;idigit;i++)
{
//将对应位的数和进位数相加
result->num[i]=result->num[i]+num2->num[i]+carry;
carry=result->num[i]/10; //计算进位数据
result->num[i]=result->num[i]%10; //保留一位
}
if(carry) //若最后还有进位
result->num[i]=result->num[i]+carry;
BigIntTrim(result); //整理结果
}
减法运算
减法运算可以看做异号加法,结果的最大位数和较大的减数位数相同,可以把被减数缺少的位数用零补全然后相减,也可以只减到被减数的位数,然后将减数的高位直接写到结果的数组中。
void BigIntSub1(pBIGINT num1,pBIGINT num2,pBIGINT result)
{
int i,borrow;
result->sign =num1->sign; //结果符号
borrow=0;
//将被减数的内容复制到结果中
for(i=0;idigit;i++)
result->num[i]=num1->num[i];
for(i=0;i<=num2->digit;i++)
{
//num1减去num2,并减去低位的借位
result->num[i]=result->num[i]-num2->num[i]-borrow;
if(result ->num[i]<0) //若为负数
{
result->num[i]=10+result->num[i]; //向高位借位
borrow=1; //设置借位数
}else
borrow=0;
}
if(borrow==1)
result->num[i]=result->num[i]-borrow;
i=num1->digit;
while(i>0)
{
if(result->num[i]==0)
i--;
else
break;
}
result->digit=i+1; //保存结果位数
BigIntTrim(result); //整理结果
}
乘法运算
对于乘法运算,以乘法的每一位去乘以被乘数。例如,首先以乘数的个位去乘被乘数,将结果通过进位处理后保存到结果位中。接着用乘数的十位去乘以被乘数,将每位计算结果累加到最终结果中。
实现代码:
两个数相乘最大的位数是两个乘数的位数之和,在乘法中我们需要每执行一次乘法就要对数组进行进位的处理。
void BigIntMul(pBIGINT num1,pBIGINT num2,pBIGINT result)
{
char carry,temp;
int i,j,pos;
//结果数组和中间数清0
for(i=0;idigit+num2->digit;i++)
result->num[i]=0;
//用乘数的每一位乘以被乘数
for(i=0;idigit;i++)
{
carry=0; //清除进位
//被乘数的每一位
for(j=0;jdigit;j++)
{
//相乘并加上进位
temp=num2->num[i] * num1->num[j]+carry;
//计算进位carry
carry =temp/10;
//计算当前位的值
temp=temp%10;
pos=i+j;
//计算结果累加到临时数组中
result->num[pos]+=temp;
carry=carry+result->num[pos]/10; //计算进位
result->num[pos]=result->num[pos]%10;
}
if(carry>0)
{
result->num[i+j]=carry; //加上最高位进位
result->digit=i+j+1; //保存结果位数
}else
result->digit=i+j; //保存结果位数
}
result->sign=num1->sign * num2->sign; //结果的符号
}
除法运算
对于大数除法运算,首先取被除数的最高两位作为部分被除数,去除以除数,根据该部分被除数与除数的结果——商,得到一位数的商。
除法对数据有限制不能分母为零,分母为零没有意义;不能用小数除以大数
void BigIntDiv(pBIGINT num1,pBIGINT num2,pBIGINT result,pBIGINT residue)
{
BIGINT residol;
int i,j,k,m; //k保存试商结果,m保存商的位数
char t;
result->sign = num1->sign * num2->sign; //商的符号
//分配余数的内存空间
residue->num =(char *)malloc(sizeof(char) * num2->digit);
for(i=0;idigit;i++) //将余数全部清0
residue->num[i]=0;
m=0;
for(i=num1->digit-1;i>=0;i--)
{
//重新设置余数的位数比除数多一位
residue->digit=num2->digit+1;
for(j=num2->digit-1;j>0;j--) //移余数
residue->num[j]=residue->num[j-1];
//复制被除数中的一位到余数的最低位中
residue->num[0]=num1->num[i];
BigIntTrim(residue); //整理余数
k=0; //试商
//比较余数与除数的大小
while(BigIntEqual(residue,num2)>=0)
{
BigIntSub1(residue,num2,residue); //用余数减去除数,差值保存在余数中
k++; //试商加1
}
result->num[m++]=k; //保存商
}
result->digit=m; //保存商的位数
for(i=0;inum[i];
result->num[i]=result->num[m-1-i];
result->num[m-1-i]=t;
}
BigIntTrim(result); //整理商
BigIntTrim(residue); //整理余数
}