Java实现大整数相加

在不使用BigInteger这个类的情况下,如何自己去实现两个超级大的数相加呢?

首先我们来看一下加法的原则: 1.同号相加,把两数相加,结果符号位取任意一个数的符号  

                                                    2.异号相加,取较大的数减去较小的数,结果符号位取较大的数的符号位

由于是超级大数,我们使用String来存储。首先要判断这两个大数的符号位,以及正确性(不能是0开头的数,也不能含有其它字母和符号)

/**
	 * 大整数求和
	 * 
	 * @param num1
	 * @param num2
	 * @return
	 */
	public static String bigNumberSum(String num1, String num2) {
		// 最后的符号
		char sign = '+';

		char sign1 = num1.charAt(0);
		char sign2 = num2.charAt(0);

		String number1 = "";
		String number2 = "";

		// 去符号位操作
		if (sign1 == '-' || sign1 == '+') {
			number1 = num1.substring(1);
		} else {
			sign1 = '+';
			number1 = num1;
		}
		// 去符号位操作
		if (sign2 == '-' || sign2 == '+') {
			number2 = num2.substring(1);
		} else {
			sign2 = '+';
			number2 = num2;
		}

		boolean isDig1 = number1.matches("[1-9][0-9]*");
		boolean isDig2 = number2.matches("[1-9][0-9]*");
		if (!isDig1 || !isDig2) {
			throw new NumberFormatException("输入的数据不是正确的整数");
		}

		return "";
	}
首先要知道的是两个数相加,结果的最大长度是两数最长的长度+1。所以我们用一个int[len]数组来存储各位相加的结果。

		int length1 = number1.length();
		int length2 = number2.length();
		// 两数相加结果最长为求最长的数的长度+1
		int len = length1 > length2 ? length1 + 1 : length2 + 1;
		int[] result = new int[len];
为了从个位开始,我们需要对字符进行反转

	char[] chars1 = new StringBuffer(number1).reverse().toString().toCharArray();
	char[] chars2 = new StringBuffer(number2).reverse().toString().toCharArray();


接着开始讨论一些情况,首先是同号相加。如果两个数的长度不一致,应该先以长度最短的数开始遍历相加,接着就是最长的数组剩下的那部分的值,因为超出部分不用相加。同号相加时会有进位的情况,最后一步 便是处理进位了。比如说99+2,2比99的长度短,所以以2的长度为临界点。result[0] = 2+9=11; 2已经遍历完了,所有剩下就是直接取值于99中剩下的位数。result[1] = 9; reuslt[0] = 11>=10所以result[0] = 11%10=1; 将进位提交到下一位result[0+1] = result[0+1] +1;以此类推,result[1] = 0, result[2] = 1;所以最终结果为101,符号为正,不做处理。
boolean longerIs1 = length1 > length2 ? true : false;

		// 同号则直接相加
		if (sign1 == sign2) {
			sign = sign1;
			if (longerIs1) {
				for (int i = 0; i < length2; i++) {
					result[i] = (chars1[i] - '0') + (chars2[i] - '0');
				}
				for (int j = length2; j < length1; j++) {
					result[j] = (chars1[j] - '0');
				}
			} else {
				for (int i = 0; i < length1; i++) {
					result[i] = (chars1[i] - '0') + (chars2[i] - '0');
				}
				for (int j = length1; j < length2; j++) {
					result[j] = (chars2[j] - '0');
				}
			}
			// 处理进位
			for (int i = 0; i < len; i++) {
				if (result[i] >= 10) {
					result[i + 1] += result[i] / 10;
					result[i] = result[i] % 10;
				}
			}

		}
接着来讨论一个整数一个负数相加的情况。长度不等,拿长的数减去短的数,便于处理借位的情况。如果长度相等,这拿较大的数减去较小的。比如说2233,2100。通过String的compareTo方法比较,获取哪个数较大。当然啦,这里是相减,所以会出现借位的情况。所有最后要对借位进行处理。

else {// 异号相加,如果length1>length2,拿长的数减去小的数
			if (longerIs1) {
				sign = sign1;
				for (int i = 0; i < length2; i++) {
					result[i] = (chars1[i] - '0') - (chars2[i] - '0');
				}

				for (int j = length2; j < length1; j++) {
					result[j] = chars1[j] - '0';
				}
			} else {
				if (length1 == length2) {
					// 拿大的数减去小的数
					boolean lager = number1.compareTo(number2)>0 ? true : false;
					if (lager) {
						sign = sign1;
						for (int i = 0; i < length1; i++) {
							result[i] = (chars1[i] - '0') - (chars2[i] - '0');
						}
					} else {
						sign = sign2;
						for (int i = 0; i < length1; i++) {
							result[i] = (chars2[i] - '0') - (chars1[i] - '0');
						}
					}
				} else {// length1<length2
					sign = sign2;
					for (int i = 0; i < length1; i++) {
						result[i] = (chars2[i] - '0') - (chars1[i] - '0');
					}

					for (int j = length1; j < length2; j++) {
						result[j] = chars2[j] - '0';
					}

				}
			}
			// 处理借位
			for (int i = 0; i < len; i++) {
				if (result[i] < 0) {
					result[i] += 10;
					result[i + 1]--;
				}
			}

		}

剩下的就是处理结果result数组了。因为长度是len>length1和length2,所以会有最高位是0的情况。比如说88+2=90,但是result的长度是3,所以result得到的结果是090,这不是我们想要的,应该把0去掉。

// 结果没有进位时的0处理
		boolean flag = true;
		StringBuffer resultStr = new StringBuffer();

		for (int i = result.length - 1; i >= 0; i--) {
			if (result[i] == 0 && flag) {
				continue;
			}
			flag = false;
			resultStr.append(result[i]);
		}

		// 符号处理
		if (sign == '-') {
			return "-" + resultStr.toString();
		} else {
			return resultStr.toString();
		}

完整代码如下

/**
	 * 大整数求和
	 * @param num1
	 * @param num2
	 * @return
	 */
	public static String bigNumberSum(String num1, String num2) {
		// 最后的符号
		char sign = '+';

		char sign1 = num1.charAt(0);
		char sign2 = num2.charAt(0);

		String number1 = "";
		String number2 = "";

		// 去符号位操作
		if (sign1 == '-' || sign1 == '+') {
			number1 = num1.substring(1);
		} else {
			sign1 = '+';
			number1 = num1;
		}
		// 去符号位操作
		if (sign2 == '-' || sign2 == '+') {
			number2 = num2.substring(1);
		} else {
			sign2 = '+';
			number2 = num2;
		}

		boolean isDig1 = number1.matches("[1-9][0-9]*");
		boolean isDig2 = number2.matches("[1-9][0-9]*");
		if (!isDig1 || !isDig2) {
			throw new NumberFormatException("输入的数据不是正确的格式的整数");
		}

		char[] chars1 = new StringBuffer(number1).reverse().toString().toCharArray();
		char[] chars2 = new StringBuffer(number2).reverse().toString().toCharArray();

		int length1 = number1.length();
		int length2 = number2.length();
		// 两数相加结果最长为求最长的数的长度+1
		int len = length1 > length2 ? length1 + 1 : length2 + 1;
		int[] result = new int[len];

		boolean longerIs1 = length1 > length2 ? true : false;

		// 同号则直接相加
		if (sign1 == sign2) {
			sign = sign1;
			if (longerIs1) {
				for (int i = 0; i < length2; i++) {
					result[i] = (chars1[i] - '0') + (chars2[i] - '0');
				}
				for (int j = length2; j < length1; j++) {
					result[j] = (chars1[j] - '0');
				}
			} else {
				for (int i = 0; i < length1; i++) {
					result[i] = (chars1[i] - '0') + (chars2[i] - '0');
				}
				for (int j = length1; j < length2; j++) {
					result[j] = (chars2[j] - '0');
				}
			}
			// 处理进位
			for (int i = 0; i < len; i++) {
				if (result[i] >= 10) {
					result[i + 1] += result[i] / 10;
					result[i] = result[i] % 10;
				}
			}

		} else {// 异号相加,如果length1>length2,拿长的数减去小的数
			if (longerIs1) {
				sign = sign1;
				for (int i = 0; i < length2; i++) {
					result[i] = (chars1[i] - '0') - (chars2[i] - '0');
				}

				for (int j = length2; j < length1; j++) {
					result[j] = chars1[j] - '0';
				}
			} else {
				if (length1 == length2) {
					// 拿大的数减去小的数
					boolean lager = number1.compareTo(number2)>0 ? true : false;
					if (lager) {
						sign = sign1;
						for (int i = 0; i < length1; i++) {
							result[i] = (chars1[i] - '0') - (chars2[i] - '0');
						}
					} else {
						sign = sign2;
						for (int i = 0; i < length1; i++) {
							result[i] = (chars2[i] - '0') - (chars1[i] - '0');
						}
					}
				} else {// length1<length2
					sign = sign2;
					for (int i = 0; i < length1; i++) {
						result[i] = (chars2[i] - '0') - (chars1[i] - '0');
					}

					for (int j = length1; j < length2; j++) {
						result[j] = chars2[j] - '0';
					}

				}
			}
			// 处理借位
			for (int i = 0; i < len; i++) {
				if (result[i] < 0) {
					result[i] += 10;
					result[i + 1]--;
				}
			}

		}

		// 结果没有进位时的0处理
		boolean flag = true;
		StringBuffer resultStr = new StringBuffer();

		for (int i = result.length - 1; i >= 0; i--) {
			if (result[i] == 0 && flag) {
				continue;
			}
			flag = false;
			resultStr.append(result[i]);
		}

		// 符号处理
		if (sign == '-') {
			return "-" + resultStr.toString();
		} else {
			return resultStr.toString();
		}

	}
在我写完上面的代码时,回头去看瞬间懵比了。那么多的if else,要看好久才能看懂这些逻辑啊。要是面试官看到这些代码,估计机会都不给了。所以打算改进一下逻辑,让整体的代码结构更加清晰易懂。从头分析一遍,我们的思路,我们可以发现同号异号这两种情况是必然要判断的,我们的代码主要用在了什么方面呢。我猜你应该发现了吧,大量的代码用来处理两个数的长度不一致的情况了。我们可以看到当它们的长度相等的时候,只需要执行一个for循环即可。

if (length1 == length2) {
<span style="white-space:pre">	</span>// 拿大的数减去小的数
	boolean lager = number1.compareTo(number2)>0 ? true : false;
	if (lager) {
		sign = sign1;
		for (int i = 0; i < length1; i++) {
		<span style="white-space:pre">	</span>result[i] = (chars1[i] - '0') - (chars2[i] - '0');
		}
	} else {
		sign = sign2;
		for (int i = 0; i < length1; i++) {
		<span style="white-space:pre">	</span>result[i] = (chars2[i] - '0') - (chars1[i] - '0');
		}
	}
}

加入相加的两个数"一开始"就是长度相等的,那么我们也不许要搞那么多的事情了,逻辑会更加清晰。所以一开始我们应该先对两个数进行预处理,让它们的长度一致。即往短的数前面补0,不存在的位置补上0。你百位上没有数字,没关系,我给你个0,然后我们再相加或者相减。改进的代码如下:

/**
	 * 求超大整数的和
	 * @param num1
	 * @param num2
	 * @return 
	 */
	public static String bigNumberSumBetter(String num1, String num2) {
		char sign = '+';
		char sign1 = num1.charAt(0);
		char sign2 = num2.charAt(0);

		String number1 = "";
		String number2 = "";

		// 去符号位操作
		if (sign1 == '-' || sign1 == '+') {
			number1 = num1.substring(1);
		} else {
			sign1 = '+';
			number1 = num1;
		}
		// 去符号位操作
		if (sign2 == '-' || sign2 == '+') {
			number2 = num2.substring(1);
		} else {
			sign2 = '+';
			number2 = num2;
		}

		boolean isDig1 = number1.matches("[1-9][0-9]*");
		boolean isDig2 = number2.matches("[1-9][0-9]*");
		if (!isDig1 || !isDig2) {
			throw new NumberFormatException("输入的数据不是正确的格式的整数");
		}

		//两个数的长度
		int length1 = number1.length();
		int length2 = number2.length();
		int len = length1>=length2? length1+1:length2+1;
		
		StringBuffer number1Buffer = new StringBuffer();
		StringBuffer number2Buffer = new StringBuffer();
		//扩展数据的长度,使它们的长度一样
		if(length1>length2){
			for(int i=0; i<length1-length2; i++){
				number2Buffer.append("0");
			}
		}else if(length1<length2){
			for(int i=0; i<length2-length1; i++){
				number1Buffer.append("0");
			}
		}
		
		number1Buffer.append(number1);
		number2Buffer.append(number2);
		
		char[] chars1 = number1Buffer.reverse().toString().toCharArray(); 
		char[] chars2 = number2Buffer.reverse().toString().toCharArray(); 
		//存储每位相加的结果
		int[] result = new int[len];
		//同号相加
		if(sign1==sign2){
			sign = sign1;
			for(int i=0; i<len-1; i++){
				result[i] = (chars1[i]-'0')+(chars2[i]-'0');
			}
			
			// 处理进位
			for (int i = 0; i < len; i++) {
				if (result[i] >= 10) {
					result[i + 1] += result[i] / 10;
					result[i] = result[i] % 10;
				}
			}
		}else {
			// 拿大的数减去小的数
			boolean lager = number1.compareTo(number2)>0 ? true : false;
			if (lager) {
				sign = sign1;
				for (int i = 0; i < len-1; i++) {
					result[i] = (chars1[i] - '0') - (chars2[i] - '0');
				}
			} else {
				sign = sign2;
				for (int i = 0; i < len-1; i++) {
					result[i] = (chars2[i] - '0') - (chars1[i] - '0');
				}
			}
			
			// 处理借位
			for (int i = 0; i < len; i++) {
				if (result[i] < 0) {
					result[i] += 10;
					result[i + 1]--;
				}
			}
		}
		
		// 结果没有进位时的0处理
		boolean flag = true;
		StringBuffer resultStr = new StringBuffer();

		for (int i = result.length - 1; i >= 0; i--) {
			if (result[i] == 0 && flag) {
				continue;
			}
			flag = false;
			resultStr.append(result[i]);
		}

		// 符号处理
		if (sign == '-') {
			return "-" + resultStr.toString();
		} else {
			return resultStr.toString();
		}
	}
代码结构更清晰了,也更容易让人读懂。



  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值