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
大整数是超出基本数据类型表示范围的整数。
一、大整数的表示
定义一个结构体:
// 大整数用结构体表示
typedef struct tagBigInt
{
int d[1000];
int len;
}BigInt;
d的每一个元素都代表大整数的一位,len记录了大整数的长度。
在定义结构体变量后,需要初始化结构体:
// 大整数初始化
void initBigInt(BigInt *bign)
{
memset(bign, 0, sizeof(bign->d));
bign->len = 0;
}
输入的数字字符串中,字符串的低位是数字的高位。将其存入数组d中时,应将字符串逆序存放,使d数组中低位存放数字的低位:
// 将数字字符串转换成BigInt,数组低位存储低位数字
BigInt change(char *s)
{
BigInt ret;
ret.len = strlen(s);
for(int i=0, j=ret.len-1; i<ret.len; i++, j--)
{
ret.d[i] = s[j] - '0';
}
return ret;
}
在显示时,将d数组从高位到低位依次输出:
// 输出BigInt,将数组逆序输出
void printBigInt(const BigInt *bign)
{
for(int i=bign->len-1; i>=0; i--)
{
printf("%d", bign->d[i]);
}
printf("\n");
}
二、大整数的比较
先判断两者len的大小。如果不相等,则长的较大;如果相等,则从高位到低位依次比较每一位。
// 比较BigInt类型的大小
int compare(BigInt a, BigInt b)
{
if(a.len > b.len)
{
return 1;
}
else if(a.len < b.len)
{
return -1;
}
else
{
//从高位开始比较每一位大小
for( int i = a.len - 1; i >= 0; i--)
{
if(a.d[i] > b.d[i])
{
return 1;
}
else if(a.d[i] < b.d[i])
{
return -1;
}
}
return 0; // 相等
}
}
三、大整数的四则运算
3.1 高精度加法
对其中一位进行加法的步骤:将该位上的两个数字与进位相加,得到的结果取个位作为该位的结果,取十位作新的进位。
// 高精度加法
BigInt add(BigInt a, BigInt b)
{
BigInt ret;
initBigInt(&ret);
int carry = 0; // 进位
for( int i = 0; i < a.len || i < b.len; i++) //以长的为界
{
int temp = a.d[i] + b.d[i] + carry; //对应位与进位相加
ret.d[ret.len++] = temp % 10; //取个位为该位结果
carry = temp / 10; //十位数作为新的进位
}
if(carry != 0)
{
ret.d[ret.len++] = carry; //进位不为0,则赋给最高位
}
return ret;
}
3.2 高精度减法
对某一位:比较被减数和减数,若不够减,则向高位借位,即被减数的高位减1,被减数加10,再进行减法;如果够减,则直接减。
// 高精度减法
BigInt sub(BigInt a, BigInt b)
{
BigInt ret;
initBigInt(&ret);
for(int i = 0; i<a.len || i<b.len; i++) //以较长的为界
{
if(a.d[i] < b.d[i])
{
a.d[i+1]--;//向高位借位
a.d[i] += 10;//当前位加10
}
ret.d[ret.len++] = a.d[i] - b.d[i];//当前位结果
}
while( ret.len - 1 >= 1 && ret.d[ret.len-1] == 0)
{
ret.len--;//去除前导0,并保证结果至少有一位
}
return ret;
}
3.3 高精度与低精度的乘法
对某一位:将该位与int型整体相乘,再与进位相加,所得结果的个位作为该位结果,高位部分作为新的进位。
//高精度*低精度
BigInt multi(BigInt a, int b)
{
BigInt ret;
initBigInt(&ret);
int carry = 0; //进位
for(int i=0; i<a.len; i++)
{
int temp = a.d[i] * b + carry;
ret.d[ret.len++] = temp % 10; //个位作为该位结果
carry = temp / 10;
}
while( carry != 0) //乘法的进位可能不止一位
{
ret.d[ret.len++] = carry % 10;
carry /= 10;
}
return ret;
}
3.4 高精度除以低精度
对某一位:上一步的余数乘以10加上该位,得到该步临时的被除数,继续进行除法。
// 高精度除以低精度
BigInt divide(BigInt a, int b, int *r)
{
BigInt ret;
initBigInt(&ret);
*r = 0;
ret.len = a.len; //被除数的每一位和商的每一位是一一对应的,先令长度相等
for(int i=a.len-1; i>=0; i--)
{
*r = *r * 10 + a.d[i];
if(*r < b)
{
ret.d[i] = 0;//不够除,该位商为0
}
else
{
ret.d[i] = *r / b; //商
*r = *r % b; //新的余数
}
}
while( ret.len - 1 >=1 && ret.d[ret.len-1] == 0)
{
ret.len--; //去除前导0,并保证结果至少有一位
}
return ret;
}
总结:大整数的运算基本上就是模拟小学做算术的过程。
在传递结构体值的时候可以传地址,效率更高。