高精度整數加法

題目描述

在計算機中,因爲處理器位寬限制,只能處理有限精度的十進制整數加減法,好比在32位寬處理器計算機中,
參與運算的操做數和結果必須在-231~231-1之間。若是須要進行更大範圍的十進制整數加法,須要使用特殊
的方式實現,好比使用字符串保存操做數和結果,採起逐位運算的方式。以下:
9876543210 + 1234567890 = ?
讓字符串 num1="9876543210",字符串 num2="1234567890",結果保存在字符串 result = "11111111100"。
-9876543210 + (-1234567890) = ?
讓字符串 num1="-9876543210",字符串 num2="-1234567890",結果保存在字符串 result = "-11111111100"。

要求編程實現上述高精度的十進制加法。
要求實現方法: 
public String add (String num1, String num2)
【輸入】num1:字符串形式操做數1,若是操做數爲負,則num1的前綴爲符號位'-'
num2:字符串形式操做數2,若是操做數爲負,則num2的前綴爲符號位'-'
【返回】保存加法計算結果字符串,若是結果爲負,則字符串的前綴爲'-'

注:
(1)當輸入爲正數時,'+'不會出如今輸入字符串中;當輸入爲負數時,'-'會出如今輸入字符串中,且必定在輸入字符串最左邊位置;
(2)輸入字符串全部位均表明有效數字,即不存在由'0'開始的輸入字符串,好比"0012", "-0012"不會出現;
(3)要求輸出字符串全部位均爲有效數字,結果爲正或0時'+'不出如今輸出字符串,結果爲負時輸出字符串最左邊位置爲'-'。

輸入描述

輸入兩個字符串

輸出描述

輸出給求和後的結果

輸入例子

9876543210
1234567890

輸出例子

11111111100

算法實現

import java.util.Scanner;

/**
 * All Rights Reserved !!!
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
//        Scanner scanner = new Scanner(Main.class.getClassLoader().getResourceAsStream("data2.txt"));
        while (scanner.hasNext()) {

            String n = scanner.next();
            String m = scanner.next();
            // 【1】方法一
            System.out.println(add(n, m));

            // 【2】方法二
//            BigInteger bi1 = new BigInteger(n);
//            BigInteger bi2 = new BigInteger(m);
//            System.out.println(bi1.add(bi2));
        }

        scanner.close();
    }

    /**
     * 大整數相加,n、m都爲天然數
     *
     * @param ns 數字
     * @param ms 數字
     * @return 結果
     */
    private static String add(String ns, String ms) {


        // ns是否爲正數
        boolean pn = ns.charAt(0) != '-';
        // ms是否爲正數
        boolean pm = ms.charAt(0) != '-';

        int[] n;
        int[] m;
        if (pn) {
            n = getNumber(ns);
        } else {
            n = getNumber(ns.substring(1));
        }

        if (pm) {
            m = getNumber(ms);
        } else {
            m = getNumber(ms.substring(1));
        }


        // 二者同號
        if (pn == pm) {
            // 進行計算
            int[] r = add(m, n);
            String rs = toNumber(r);

            // 根據須要添加負號
            if (pn) {
                return rs;
            } else {
                return "-" + rs;
            }
        } else {
            // ns的絕對值比大於等於ms
            if (compare(n, m) >= 0) {
                int[] r = minus(n, m);
                String rs = toNumber(r);
                // ns爲正數,ms爲負數
                if (pn) {
                    return rs;
                } else {
                    return "-" + rs;
                }
            }
            // ns的絕對值比小於ms
            else {
                int[] r = minus(m, n);
                String rs = toNumber(r);

                // ns爲正數,ms爲負數
                if (pn) {
                    return "-" + rs;

                } else {
                    return rs;
                }
            }
        }
    }

    /**
     * 兩個整數相加
     *
     * @param m 整數
     * @param n 整數
     * @return 結果
     */
    private static int[] add(int[] m, int[] n) {

//        System.out.println(Arrays.toString(n) +"\n"+ Arrays.toString(m));

        // 保證n不小於m
        if (m.length > n.length) {
            int[] t = m;
            m = n;
            n = t;
        }

        // 結果的最大長度
        int[] r = new int[n.length + 1];
        // 來自低位的進位
        int c = 0;

        for (int i = 0; i < m.length; i++) {
            r[i] = m[i] + n[i] + c;
            c = r[i] / 10;
            r[i] %= 10;
        }

        // 計算餘下的部分
        for (int i = m.length; i < n.length; i++) {
            r[i] = n[i] + c;
            c = r[i] / 10;
            r[i] %= 10;
        }

//        System.out.println(Arrays.toString(n) +"\n"+ Arrays.toString(m) + "\n" + Arrays.toString(r));

        // 最後還有進位
        if (c != 0) {
            r[r.length - 1] = c;
            return r;
        }
        // 沒有進位
        else {
            int[] ret = new int[r.length - 1];
            System.arraycopy(r, 0, ret, 0, ret.length);
            return ret;
        }
    }


    /**
     * 比較兩個整數是否相等,下標由小到大表示由低位到高位,忽略最高有效位上的前導0
     *
     * @param m 整數
     * @param n 整數
     * @return m > n返回1,m = n返回0,m < n返回-1
     */
    private static int compare(int[] m, int[] n) {

        if (m == null && n == null) {
            return 0;
        }
        // null最小
        if (m == null) {
            return -1;
        }

        if (n == null) {
            return 1;
        }

        int lastM = m.length - 1;
        int lastN = n.length - 1;

        // 找m的最高有效位的位置,至少有一位
        while (lastM >= 1 && m[lastM] == 0) {
            lastM--;
        }
        // 找n的最高有效位的位置,至少有一位
        while (lastN >= 1 && n[lastN] == 0) {
            lastN--;
        }

        // m的數位比n多,說明m比n大
        if (lastM > lastN) {
            return 1;
        }
        // m的數位比n少,說明m比n小
        else if (lastM < lastN) {
            return -1;
        } else {
            // 位數同樣,比較每個數位上的值,從高位到低位進行比較
            for (int i = lastM; i >= 0; i--) {
                if (m[i] > n[i]) {
                    return 1;
                } else if (m[i] < n[i]) {
                    return -1;
                }
            }

            return 0;
        }
    }


    /**
     * 作減法n-m,保證n大於等於m
     *
     * @param n 整數
     * @param m 整數
     * @return 結果
     */
    private static int[] minus(int[] n, int[] m) {

        n = format(n);
        m = format(m);

        int[] r = new int[n.length];

        // 當前位被借位
        int c = 0;
        int t;
        for (int i = 0; i < m.length; i++) {
            t = n[i] - c - m[i];
            // 當前位夠減
            if (t >= 0) {
                r[i] = t;
                // 沒有進行借位
                c = 0;
            }
            // 不夠減
            else {
                r[i] = t + 10;
                // 進行借位
                c = 1;
            }
        }

         // 還有借位或者n比m位數多,要將n中的數位複製到r中
        for (int i = m.length; i < n.length; i++) {
            t = n[i] - c;
            // 當前位夠減
            if (t >= 0) {
                r[i] = t;
                // 沒有進行借位
                c = 0;
            }
            // 不夠減
            else {
                r[i] = t + 10;
                // 進行借位
                c = 1;
            }
        }

        return format(r);
    }


    /**
     * 將整數字符串表示成整數數組【包含符號位】
     *
     * @param n 整數字符串
     * @return 整數數組 下標從小到大表示數位的從低到高
     */
    private static int[] getNumber(String n) {
        int[] r = new int[n.length()];
        for (int i = 0; i < r.length; i++) {
            r[i] = n.charAt(n.length() - i - 1) - '0';
        }

        return r;
    }

    /**
     * 將整數進行格式化,去掉高位的前導0
     *
     * @param r 整數
     * @return 結果
     */
    private static int[] format(int[] r) {
        int t = r.length - 1;
        // 找最高有效位
        while (t > 0 && r[t] == 0) {
            t--;
        }

        int[] nr = new int[t + 1];
        System.arraycopy(r, 0, nr, 0, nr.length);
        return nr;

    }


    /**
     * 將數組表示的整數轉換成字符串
     *
     * @param r 整數
     * @return 字符串表示的整數
     */
    private static String toNumber(int[] r) {
        if (r == null) {
            return null;
        }

        StringBuilder b = new StringBuilder(r.length);

        for (int i = r.length - 1; i >= 0; i--) {
            b.append(r[i]);
        }

        return b.toString();
    }
}
相關文章
相關標籤/搜索