题目描述
高精度减法。
输入格式
两个整数 a,b(第二个可能比第一个大)。
输出格式
结果(是负数要输出负号)。
输入输出样例
输入
2 1输出
1说明/提示
- 20% 数据 a,b 在 long long 范围内;
- 100% 数据 0<a,b≤10^10086。
个人踩坑:1.为什么不能直接用int数组接收数据,而是要用字符串输入??
2.被减数大于减数的情况和减数大于被减数的情况有什么不同??
3.倒置后的消零处理
一,
对于32位计算机而言,int的范围是2^31-1>int>-2^31,而本题的数字大小远远超过。因此不能用int甚至longlong也不行。
本人的错误在于,错误地认为通过int数组输入时,会如同string类型一样,每个位置只有0~9。事实上,当我输入13时,接收到的并不是1,3,而是13。(当个笑话看就行)。
因此必须先由字符串输入,再通过int数组接收。
二,
1. 当被减数大于减数时,非常正常按照我们小学老师教我们的方法计算就行。
2 0 0
- 1 9 9
——————————
0 0 1
(至于消去零的操作移步第三)
下面先看看我的错误代码,还没经过对应二,三错误的修改,正确代码在最后:
#include <iostream>
#include <string>
using namespace std;
//高精度减法
string A, B;
int a[1000000], b[1000000], c[10000000];
void swap(char *a, char *b) {
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int i = 0, j = 0;
cin >> A >> B;
//首先要得到a,b的字符串长度
int len_a = 0, len_b = 0, len_max, temp = 0;
for (i = 0; A[i] != '\0'; i++)
len_a++;
for (j = 0; B[j] != '\0'; j++)
len_b++;
//赋值int数组
/*然后将a,b的字符串分别进行倒序,方便向后一位借1:
例如:输入时是550和350,高位在前,倒序后为055和053,高位在后*/
for (i = 0; i < len_a; i++)
a[len_a - i - 1] = A[i] - '0';
for (j = 0; j < len_b; j++)
b[len_b - j - 1] = B[j] - '0';
//进行高精度减法:1.先得到长的数字长度
len_max = len_a > len_b ? len_a : len_b;
//调试
/*for (i = 0; i < len_max; i++)
cout << "a=" << *(a + i) << endl;
for (j = 0; j < len_max; j++)
cout << "b=" << *(b + j) << endl;*/
//计算:
for (i = 0; i < len_max; i++) {
c[i] = a[i] - b[i] + temp;//temp为借位操作,当上一位小于0时
if (c[i] < 0) {
temp = -1;
c[i] += 10;
} else {
temp = 0;
}
}
if (temp == -1) {
cout << "-";
for (i = len_max - 1; i >= 0; i--)//倒序输出,若最后的temp还为0,为负数
cout << c[i];
} else if (temp == 0) {
for (i = len_max - 1; i >= 0 ; i--)
cout << c[i];
}
return 0;
}
2.但是当被减数小于减数时,则不同:
按照错误代码计算的逻辑如下:
2 0 0
- 3 9 9
——————————————
- 1 1 1
其实当被减数小于减数时应该倒过来:先换位被减数和减数,再正常计算后,前面加上“-”
- ( 3 9 9 )
( 2 0 0 )
——————————————————
- 1 9 9
(我是sb我这都不知道)
因此必须比较被减数和减数的大小:
运用字符串比较大小:(精髓)由于字符串比较时,只会逐位比较,因此
9 > 80???所以必须加上长度限制。
if (A < B && len_a == len_b || len_a < len_b)
三,消去无用的零
比如100000000-100000000时,未消去0则会输出000000000。
因此必须消去。消零代码如下:
//还需要进行消零操作:有时需要的是1,而不是000001
for (i = len_max - 1; i >= 0 ; i--) {
if (c[i] == 0 && i > 0)/*当最后一位为零时不可删除,其余前面的零删除,
但是比如200-300=-100,其中后面的零不可以删除,所以选择缩短数列长度,
如此只可能删除有效数字前面的零*/
len_max--;
else
break;
}
正确代码如下:(de死我了)
#include <iostream>
#include <string>
using namespace std;
//高精度减法
string A, B;
int a[1000000], b[1000000], c[10000000];
void swap(char *a, char *b) {
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int i = 0, j = 0;
cin >> A >> B;
//首先要得到a,b的字符串长度
int len_a = 0, len_b = 0, len_max, temp = 0;
for (i = 0; A[i] != '\0'; i++)
len_a++;
for (j = 0; B[j] != '\0'; j++)
len_b++;
//赋值int数组
/*然后将a,b的字符串分别进行倒序,方便向后一位借1:
例如:输入时是550和350,高位在前,倒序后为055和053,高位在后*/
for (i = 0; i < len_a; i++)
a[len_a - i - 1] = A[i] - '0';
for (j = 0; j < len_b; j++)
b[len_b - j - 1] = B[j] - '0';
//进行高精度减法:1.先得到长的数字长度
len_max = len_a > len_b ? len_a : len_b;
//调试
/*for (i = 0; i < len_max; i++)
cout << "a=" << *(a + i) << endl;
for (j = 0; j < len_max; j++)
cout << "b=" << *(b + j) << endl;*/
//计算:先判断被减数和减数哪个大,减数大则要换位
if (A < B && len_a == len_b || len_a < len_b) { //通过字符串比较大小,可以得知两个数字的大小
for (i = 0; i < len_max; i++) {
c[i] = b[i] - a[i] + temp;//temp为借位操作,当上一位小于0时
if (c[i] < 0) {
temp = -1;
c[i] += 10;
} else {
temp = 0;
}
}
//temp一定等于-1
cout << "-";
//还需要进行消零操作:有时需要的是1,而不是000001
for (i = len_max - 1; i >= 0 ; i--) {
if (c[i] == 0 && i > 0)/*当最后一位为零时不可删除,其余前面的零删除,
但是比如200-300=-100,其中后面的零不可以删除,所以选择缩短数列长度,
如此只可能删除有效数字前面的零*/
len_max--;
else
break;
}
for (i = len_max - 1; i >= 0; i--)
cout << c[i];
} else {
for (i = 0; i < len_max; i++) {
c[i] = a[i] - b[i] + temp;//temp为借位操作,当上一位小于0时
if (c[i] < 0) {
temp = -1;
c[i] += 10;
} else {
temp = 0;
}
}
//temp一定等于0
for (i = len_max - 1; i >= 0 ; i--) {
if (c[i] == 0 && i > 0)//同样进行消零操作
len_max--;
else
break;
}
for (i = len_max - 1; i >= 0 ; i--) {
cout << c[i];
}
return 0;
}
}