天天看點

一個一百億的電腦的實作MyBigInteger.javaMyBigIntegerTest.java

網上一搜一大把,搜出來的結果幾乎都是我很崇敬的張孝祥老師寫的這道題的思路,甚至有的直接把原文copy paste過來,沒有一個用代碼實作了的。于是自己琢磨了下,這裡釋出出來。雖然标題是一百億,但實作結果可用于任意大整數。

直接上代碼。這裡隻實作了大整數相加。有了這個,不難實作減、乘等其他操作。代碼複制粘帖即可運作。

MyBigInteger.java

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by Rocky on 14-3-26.
 */
public class MyBigInteger {
    private char sign = '0';   // 0 表示正數  - 表示負數
    private byte[] data;

    public MyBigInteger() {
        this.data = "0".getBytes();
    }

    public MyBigInteger(String value) throws Exception {
        //正規表達式,輸入字元串要求以 零個或一個 - 開頭,其餘都是數字
        Pattern pattern = Pattern.compile("^-?\\d+$");

        if (value == null || value.length() <= 0) {
            value = "0";
        }
        Matcher matcher = pattern.matcher(value);
        if (!matcher.find()) {
            throw new Exception("the value is not a number string :" + value);
        }
        //擷取字元串的第一個字元
        char firstChar = value.charAt(0);

        //data應該儲存的是第一個非0數字後的字元串
        if (firstChar == '-') {  //說明輸入的是個負數
            if (value.length() >=2) {
                sign = firstChar;
                value = value.substring(1);
                value = getTemp(value); //得到value中第一個非0後的子字元串。
            }
        } else {
            value = getTemp(value);
        }
        this.data = value.getBytes();
    }

    /**
     * 得到一個字元串第一個非0後的字元串,如果沒有找到,則傳回 "0" 。如:00003435534,則傳回3435534
     * @return
     */
    private String getTemp(String value){
        Pattern pattern = Pattern.compile("[^0]{1}");
        Matcher matcher = pattern.matcher(value);
        if (matcher.find()) {
            value = value.substring(matcher.start());
        } else {
            value = "0";
        }
        return value;
    }

    public MyBigInteger add(MyBigInteger other) {
        MyBigInteger result = new MyBigInteger();
        int thisLength = this.data.length;
        int otherLength = other.data.length;
        int shorterLength = thisLength > otherLength ? otherLength : thisLength;
        ArrayList<Byte> resultData = new ArrayList<Byte>();
        int flag = 0;  //表示相加時的 進位,或相減時的 借位
        int i = thisLength - 1;
        int j = otherLength - 1;
        int k = shorterLength;

        //兩個數的符号相同
        if (other.sign == this.sign) {
            //從兩個整數的個位開始依次相加
            while (k > 0) {
                Integer temp = new Integer(new String(new byte[]{this.data[i]})) + new Integer(new String(new byte[]{other.data[j]})) + flag;
                flag = temp / 10;  //相加結果超過10時的進位。沒有超過10,進位為 0
                resultData.add(0, ((temp % 10) + "").getBytes()[0]);  //把相加結果儲存起來
                k--;
                i--;
                j--;
            }
            //把多出的位加入到結果中
            if (i == -1) {
                while (j >= 0) {
                    Integer temp = new Integer(new String(new byte[]{other.data[j]})) + flag;
                    flag = temp / 10;
                    resultData.add(0, ((temp % 10) + "").getBytes()[0]);
                    j--;
                }
            } else if (j == -1) {
                while (i >= 0) {
                    Integer temp = new Integer(new String(new byte[]{this.data[i]})) + flag;
                    flag = temp / 10;
                    resultData.add(0, ((temp % 10) + "").getBytes()[0]);
                    i--;
                }
            }
            //最後把flag加進結果中
            if (flag != 0) {
                for (byte by : (flag + "").getBytes()) {
                    resultData.add(0, by);
                }
            }
            result.sign = other.sign;
        } else {  //符号不同
            if (thisLength > otherLength) {  //說明this表示的整數絕對值大,是以最終結果的符号為this的符号
                result.sign = this.sign;
                resultData = subtract(this.data, other.data);  //執行減法
            } else if (thisLength < otherLength) {  //other表示的整數絕對值大,是以最終結果的符号為other的符号
                result.sign = other.sign;
                resultData = subtract(other.data, this.data);
            } else {  //如果兩個資料的位數相同
                Integer thisInt = 0;
                Integer otherInt = 0;
                //從第一位開始比較,直到兩者不相等
                for (int n = 0; n < thisLength; n++) {
                    thisInt = new Integer(new String(new byte[]{this.data[n]}));
                    otherInt = new Integer(new String(new byte[]{other.data[n]}));
                    if (!thisInt.equals(otherInt)) {   //注意這裡要使用equals方法,因為這裡需要比較的是兩者的内容
                        break;
                    }
                }

                //如果this的絕對值大
                if (thisInt > otherInt) {
                    result.sign = this.sign;
                    resultData = subtract(this.data, other.data);
                } else {
                    result.sign = other.sign;
                    resultData = subtract(other.data, this.data);
                }
            }
        }
        result.data = new byte[resultData.size()];
        for (int m = 0; m < resultData.size(); m++) {
            result.data[m] = resultData.get(m);
        }
        return result;
    }

    private ArrayList<Byte> subtract(byte[] larger, byte[] smaller) {
        ArrayList<Byte> resultData = new ArrayList<Byte>();
        int flag = 0;
        int i = smaller.length - 1;
        int j = larger.length - 1;
        int k = smaller.length;
        while (k > 0) {
            Integer temp = new Integer(new String(new byte[]{larger[j]})) + flag - new Integer(new String(new byte[]{smaller[i]}));
            if (temp < 0) { //如果相減結果小于0,說明需要借位,則把flag置為 -1,以便下一位減去
                flag = -1;
                temp += 10;
            } else {       //如果大于零,需要把flag置為 0.不要忘記了
                flag = 0;
            }
            resultData.add(0, (temp + "").getBytes()[0]);
            j--;
            i--;
            k--;
        }
        //下面的代碼就不寫注釋了
        while (j >= 0) {
            Integer temp = new Integer(new String(new byte[]{larger[j]})) + flag;
            if (temp < 0) {
                flag = -1;
                temp += 10;
            } else {
                flag = 0;
            }
            resultData.add(0, (temp + "").getBytes()[0]);
            j--;
        }
        return resultData;
    }


    @Override
    public String toString() {
        String str = new String(this.data);
        str = getTemp(str);
        if (sign == '-' && str !="0") {
            str = sign + str;
        }
        return str;
    }

}
           

MyBigIntegerTest.java

import junit.framework.TestCase;
import java.math.BigInteger;

/**
 * Created by Rocky on 14-3-26.
 */
public class MyBigIntegerTest extends TestCase {
    public void test1() throws Exception {
        String a1 = "-5453450543044355356576980545345054545453453454344435353254545345054304435535657698087756454543454345454534534543444353532545453450543044355356454543454354353450136546534534545345345054353450136546534534545345345043044355356576980657698087756454543454354353450136546534534545345345054353450136546534534545345345043044355356576980877564545434543543534501877564545434543543534501";
        String b1 = "4545453453454344435353254545345054304435535657698087756454543454354345454534534543444353532545453450543044355356576980877564545434545454534534564545434543543534501365465345345453453450543534501365465345345453453450430443553565769804344435353254545345054304435535657698087756454543454354353450136546534534545345345043543534501365465345345453453450534501365465345345453453450";
        MyBigInteger a = new MyBigInteger(a1);
        MyBigInteger b = new MyBigInteger(b1);
        MyBigInteger c = a.add(b);
        System.out.println(c);
        BigInteger a2 = new BigInteger(a1);
        BigInteger b2 = new BigInteger(b1);
        BigInteger c2 = a2.add(b2);
        System.out.println(c2);
        System.out.println(c2.toString().equals(c.toString()));
    }
}
           

結果:

繼續閱讀