Java实现字符串形式大数相加
思路还是比较清晰,用自定义类型保存输入的数据,逐位相加/相减,需要处理好借位及符号。
总共两个类,一个自定义类型Int,一个AddUtil封装加法操作。附带测试类AddUtilTest。代码如下:
Int.java:
package cn.areful; /** * Created by areful, 2020/05/02 */ public class Int { //符号 public boolean isPositive = true; //有效长度 public int len; //各位位数 public int[] digits; public Int(boolean flag, int len) { isPositive = flag; this.len = len; digits = new int[len]; } public Int(String s) { checkValid(s); char fst = s.charAt(0); String tmp; if (fst == '+' || fst == '-') { isPositive = fst != '-'; len = s.length() - 1; tmp = s.substring(1); } else { len = s.length(); tmp = s; } digits = new int[len]; //各位数逆序存放 for (int i = 0; i < len; i++) { digits[i] = tmp.charAt(len - 1 - i) - '0'; } } //检查输入是否合法. private static void checkValid(String s) { if (!s.matches("(0|([+-]?[1-9]+[0-9]*))")) { throw new RuntimeException("Invalid String number: " + s); } } //去除结果之前多余的0 public Int stripZero() { for (int i = len - 1; i >= 0; i--) { if (digits[i] != 0) { break; } len--; } int[] tmp = new int[len]; if (len >= 0) { System.arraycopy(digits, 0, tmp, 0, len); } digits = tmp; return this; } @Override public String toString() { //逆序输出 StringBuilder sb = new StringBuilder(); for (int i = len - 1; i >= 0; i--) { sb.append(digits[i]); } return !isPositive ? "-" + sb : sb.toString(); } }
AddUtil.java:
package cn.areful; /** * Created by areful, 2020/05/02 */ public class AddUtil { public static Int add(Int i1, Int i2) { if (i1.isPositive && i2.isPositive) { //都为正数,各位相加,符号为正 return addPositive(i1, i2); } else if (!i1.isPositive && !i2.isPositive) { //都为负数,各位相加,符号为负 Int r = addPositive(i1, i2); r.isPositive = false; return r; } //以下为一正一负 if (i1.len > i2.len) { //第一个数较长,符号取第一个数符号,各位相减 return subPositive(i1, i2); } else if (i1.len < i2.len) { //第二个数较长,符号取第二个数符号,各位相减 return subPositive(i2, i1); } //两数长度相等,逐位判断大小 for (int i = i1.len - 1; i >= 0; i--) { int d1 = i1.digits[i]; int d2 = i2.digits[i]; //想等则比较下一位 if (d1 == d2) continue; if (d1 > d2) { //第一个数绝对值较大,取第一个数符号,各位相减 return subPositive(i1, i2); } else { //第二个数绝对值较大,符号取第二个数符号,各位相减 return subPositive(i2, i1); } } //两数相等,返回0 return new Int("0"); } //两个正整数相加 private static Int addPositive(Int i1, Int i2) { int maxLen = Math.max(i1.len, i2.len); Int r = new Int(true, maxLen + 1); int carry = 0; for (int i = 0; i < maxLen; i++) { int c1 = i >= i1.len ? 0 : i1.digits[i]; int c2 = i >= i2.len ? 0 : i2.digits[i]; int c = c1 + c2 + carry; carry = c > 9 ? 1 : 0; r.digits[i] = c % 10; } if (carry == 1) { r.digits[maxLen] = 1; r.len = maxLen + 1; } else { r.len = maxLen; } return r; } //两个正整数相减,第一个数要大于第二个数 private static Int subPositive(Int i1, Int i2) { Int r = new Int(i1.isPositive, i1.len); int carry = 0; for (int i = 0; i < i1.len; i++) { int c1 = i1.digits[i] + carry; int c2 = i >= i2.len ? 0 : i2.digits[i]; if (c1 < c2) { carry = -1; c1 += 10; } else { carry = 0; } int c = c1 - c2; r.digits[i] = c % 10; } return r.stripZero(); } }
AddUtilTest:
package cn.areful; import org.junit.Assert; import org.junit.Test; /** * Created by areful, 2020/05/02 */ public class AddUtilTest { @Test public void testPositiveAdd() { Assert.assertEquals(AddUtil.add(new Int("1234"), new Int("1234")).toString(), "2468"); Assert.assertEquals(AddUtil.add(new Int("456"), new Int("789")).toString(), "1245"); Assert.assertEquals(AddUtil.add(new Int("0"), new Int("1000")).toString(), "1000"); } @Test public void testNegativeAdd() { Assert.assertEquals(AddUtil.add(new Int("-1234"), new Int("-1234")).toString(), "-2468"); Assert.assertEquals(AddUtil.add(new Int("-150"), new Int("-1550")).toString(), "-1700"); } @Test public void testFixedAdd() { Assert.assertEquals(AddUtil.add(new Int("1234"), new Int("-1234")).toString(), "0"); Assert.assertEquals(AddUtil.add(new Int("1500"), new Int("-155")).toString(), "1345"); Assert.assertEquals(AddUtil.add(new Int("-150"), new Int("1550")).toString(), "1400"); Assert.assertEquals(AddUtil.add(new Int("0"), new Int("0")).toString(), "0"); Assert.assertEquals(AddUtil.add(new Int("0"), new Int("-1234")).toString(), "-1234"); Assert.assertEquals(AddUtil.add(new Int("-1234"), new Int("0")).toString(), "-1234"); } }