高精度减法(个人详解版)

题目描述

高精度减法。

输入格式

两个整数 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;
	}
}

  • 47
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值