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");
    }
}

  

 

posted on 2020-05-02 17:55  areful  阅读(668)  评论(0编辑  收藏  举报

导航