大整数运算结构体
struct bign {
int d[maxn];//d的低位就是数值N的低位
int len;//大整数长度
//int symbol;
bign() {
memset(d, 0, sizeof(d));
len = 0;
//symbol = 1;
}
};
字符串转化为大整数型
bign str2bign(char str[]) {
bign num;
int len = strlen(str);
if (str[0] == '-')num.symbol = -1;//如果是负数
for (int i = 0; i < len; i++) {
if (str[len - i - 1] == '-')continue;
num.d[num.len] = str[len - i - 1] - '0';
num.len++;
}
while (num.len > 1 && num.d[num.len - 1] == 0)num.len--;//消除前缀0
return num;
}
大整数(绝对值)比较大小
int compare(bign x, bign y) {
if (x.len > y.len)return 1; // 越长的数越大
else if (x.len < y.len)return -1;
else { // 相同长度,从高位开始向低位逐位比较
for (int i = x.len - 1; i >= 0; i--) {
if (x.d[i] > y.d[i])return 1;
else if (x.d[i] < y.d[i])return -1;
}
return 0;
}
}
加法(绝对值)
bign add(bign x, bign y) {
bign z;
int t, carry = 0;//t用来保存某位的运算,carry用来保存进位的大小
for (int i = 0; i < x.len || i < y.len; i++) {
t = x.d[i] + y.d[i] + carry;
z.d[z.len++] = t % 10;
carry = t / 10;
}
if (carry != 0)z.d[z.len++] = carry;//最后的进位
return z;
}
减法(绝对值) |x|>|y|
bign sub(bign x, bign y) {
bign z;
for (int i = 0; i < x.len || i < y.len; i++) {
if (x.d[i] < y.d[i]) { // 不够减
x.d[i + 1] -= 1;//向高位借位
x.d[i] += 10;
}
z.d[z.len++] = x.d[i] - y.d[i];
}
while (z.len > 1 && z.d[z.len - 1] == 0)z.len--;//消去高位多余的0
return z;
}
低精度乘法(绝对值):
思想:x ✖️ y,假设x是bign类型,y是int类型,我们把x看作是由一个数组组成的数,而把y看作是一个整体
从低位开始遍历x数组每位的数x.d[i],令 t = x.d[i] * y,这样的话,t%10就是但前位的值,t/10就是进位的大小,我们用carry记录进位
那么高一位的运算过程就是 t = x.d[i] * y + carry ,接着执行同样的步骤,取低位,把(进位)高位赋值到carry
bign multi(bign x, int y) {
bign z;
int carry = 0, t;
for (int i = 0; i < x.len; i++) {
t = x.d[i] * y + carry; //x的每位与y整体相乘
z.d[z.len++] = t % 10; // 取低位为z但前位的值
carry = t / 10; //取高位为进位
}
while (carry != 0) {
z.d[z.len++] = carry % 10;
carry /= 10;
}
return z;
}
低精度除法(绝对值):
把x看作是由一个数组组成的大整数,把y看作是一个整体,令r为余数(初始为0)
从x的高位开始遍历,对x的每一位x.d[i] ,都令新的余数为r = r*10+x.d[i]
与b位相对应的商= r / y ,更新余数r=r%y
// x/y
bign devide(bign x, int y, int &r) { //r 为余数
bign z;
r = 0;
z.len = x.len;
for (int i = x.len - 1; i >= 0; i--) { //从x的高位开始遍历
r = r * 10 + x.d[i];//和上一位遗留的余数组合
z.d[i] = r / y; //商
r = r%y; // 取余
}
while (z.len > 1 && z.d[z.len - 1] == 0)z.len--;//消除前缀0
return z;
}
带符号加法运算
bign x = str2bign(str1);
bign y = str2bign(str2);
if (x.symbol * y.symbol > 0) { //如果两个数同号
if (x.symbol == -1)printf("-"); //且都为负数
print(add(x, y));
}
else if (x.symbol == 1 && y.symbol == -1) { //如果x>0,y<0
if (compare(x, y) >= 0) { // |x|>=|y| ,那么x+y是正数
print(sub(x, y));//绝对值相减,大的减去小的
}
else {// |x|<=|y| ,那么x+y是负数
printf("-");
print(sub(y, x));//绝对值相减,大的减去小的
}
}
else {
if (compare(x, y) <= 0) { //同理
print(sub(y, x));
}
else {
printf("-");
print(sub(x, y));
}
}