當簡單的計算遇上了大數,其實大數運算也很簡單

一、說三道四

用代碼實現簡單的加減乘除運算會不會?只要你是個coder,我想這個答案都是肯定的吧!

但是,今天我想說的是,當我們的運算遇到了大數,用原本的int、long、float、double數值類型

都無法表示出來的時候,你們想過該如果解決這一類型的問題了嗎?

在這,你們可以先不用看鹵煮擼的代碼,想想如果自己遇到這個問題,該如果解決,也許你的想法

很新穎,思路以及在算法的實現上更清晰。希望能夠在廣大的博友的集思廣益下,大數的運算能夠有

一套更好的解決方案。不說了,咱們先擼代碼吧。畢竟這才是主題!!!

二、大數運算之加法運算


package com.linjm.work;

public class Add {

public String forAdd(String p, String q) {
    String x = p;
    String y = q;

    int len = 0;
    String res = "";

    len = (x.length() > y.length()) ? x.length() : y.length();


    if (len == x.length())    y = Tools.fillZero(y, x.length() - y.length());
    if (len == y.length())    x = Tools.fillZero(x, y.length() - x.length());

    x = Tools.reverse(x);
    y = Tools.reverse(y);

    //m,n用于循環遍歷時截取字符串x,y的每一位
    //flag用于標識m和n的每一次相加是否需要進位
    int m, n, flag = 0;

    //遍歷x、y,對應位相加
    for (int i = 0; i < len; i++) {
        int sum;

        m = Integer.parseInt(x.substring(i, i + 1));
        n = Integer.parseInt(y.substring(i, i + 1));
        sum = m + n;

        if (flag == 1) {    
            sum = sum + 1;
            flag = 0;
        }

        if (sum >= 10) {
            flag = 1;
            sum = sum - 10;
        }

        res += sum;
    }

    if (flag == 1)    //最高位相加后還大于10,則須進位
        res += "1";

    return Tools.reverse(res);
}



public static void main(String[] args) {
    Add add = new Add();
    System.out.println(add.forAdd("555555555555555555", "5555555555555555551"));
}

}

大數相加</code></pre>

思路分析:

大數的相加主要是通過字符串的相加來實現的。兩個大數相加,找出位數較大的那個大數獲取對應的長度,

然后對較小的那個數進行左補0直至長度和較大的那個數的位數一樣,最后循環累加兩個大數的每一位的數值,

遇到需要進位的需要設一個標識位標識。

三、大數運算之減法運算


package com.linjm.work;

public class Sub {

public String forSub(String p, String q) {
    String x = p;
    String y = q;

    int len = 0;
    String res = "";

    int sign = 0;    //0: x >= y、1: x < y 
    sign = Tools.forMax(x, y) ? 0 : 1;

    if (sign == 1) {
        x = q;
        y = p;
    }

    len = x.length();

    y = Tools.fillZero(y, x.length() - y.length());

    int m, n, flag = 0, num = 0;    //num標識出現0的次數,防止結果中高位出現多個0的情況

    for (int i = len; i > 0; i--) {
        int dif;

        m = Integer.parseInt(x.substring(i - 1, i));
        n = Integer.parseInt(y.substring(i - 1, i));

        dif = m - n;

        //標志位如果等于1,說明存在借位
        if (flag == 1) {
            dif = dif - 1;
            flag = 0;    //重置標志位
        }

        //判斷是否需要借位
        if (dif < 0) {
            flag = 1;    //標記
            dif = dif + 10;
        }

        if (dif == 0) {
            num ++;
        } else {
            num = 0;
        }

        res += dif;
    }

    if (Tools.isZero(res))
        return "0";

    if (num > 0) {
        res = res.substring(0, res.length() - num);    //截取掉高位出現的連續num個0
    }

    return (sign == 1) ? "-" + Tools.reverse(res) : Tools.reverse(res);
}



public static void main(String[] args) {
    Sub sub = new Sub();
    System.out.println(sub.forSub("100000000", "1"));
}

}

大數相減</code></pre>

思路分析:

大數相減在實現上和大數相加異曲同工,也是通過循環遍歷大數的每一位,對其進行數值相減,在遇到需要借位的數值,

設立一個標識位進行標識。當遇到被減數比減數小的時候,先用減數減去被減數,用標識位標識被減數比減數小,最后結果

根據標識變量判斷是否需要在結果上加上"-"。

四、大數運算之乘法運算


package com.linjm.work;

public class Mul {

public String forMul(String p, String q) {
    String x = Tools.maxNum(p, q);
    String y = Tools.minNum(p, q);

    if (y.length() > 15) {
        return "ERROR:兩位數中必須有一個數的長度要小于15";
    }

    String sum = "0";

    Add add = new Add();
    Sub sub = new Sub();

    while (Long.parseLong(y) > 0) {
        sum = add.forAdd(sum, x);
        y = sub.forSub(y, "1");
    }

    return sum;
}



public static void main(String[] args) {
    Mul mul = new Mul();
    System.out.println(mul.forMul("1000", "20000"));
}

}

大數相乘</code></pre>

思路分析:

大數相乘在算法的實現上個人表示有點不太滿意,雖然實現了功能,但還是覺得代碼的實現上和思路都很挫。

乘法的最終思路就是多個數值的加法運算。所以大數的乘法就是多個大數的加法運算。但是遇到兩個數值都是大數的情況下,

運行速度會非常的慢。

五、大數運算之除法運算


package com.linjm.work;

public class Div {

public String forDiv (String p, String q) {
    String x = p;
    String y = q;

    String res = "0";
    String remain = "0";    //余數

    if (!Tools.forMax(x, y)) {
        return x + "的值要大等于" + y; 
    }

    Add add = new Add();
    Sub sub = new Sub();

    while (true) {
        x = sub.forSub(x, y);
        res = add.forAdd(res, "1");

        if (!Tools.forMax(x, y)) {
            remain = x;
            break;
        }
    }

    if (!Tools.isZero(remain))
        res = res + "……" +remain;

    return res;
}



public static void main(String[] args) {
    Div div = new Div();
    System.out.println(div.forDiv("222222222222222222222", "222222222222222222221"));
}

}

大數相除</code></pre>

思路分析:

除法運算的實質也就是減法,讓被除數一直減去除數,直到減不動了為止,統計下減了多少次除數,這個值就是商咯。

但是存在的問題還是和大數的乘法是一樣的,有待優化。

六、大數運算之工具類


package com.linjm.work;

public class Tools {

/**
 * @param s num
 * @Desc 字符串左補num個0
 * @return String
 * */
public static String fillZero(String s, int num) {
    String res = "";

    for (int i = 0; i < num; i++) {
        res += "0";
    }

    return res + s;
}

/**
 * @param s
 * @Desc 反轉字符串
 * @return String
 * */
public static String reverse(String s) {
    String res = "";

    for (int i = s.length(); i > 0 ; i--) {
        res +=  s.substring(i - 1, i);
    }

    return res;
}

/**
 * @param x n(n最小值為1)
 * @Desc 獲取字符串的n個字符
 * @return int
 * */
public static int numAt(String x, int n) {
    return Integer.parseInt(x.substring(n - 1, n));
}


/**
 * @param x y
 * @Desc 獲取兩個大數中較大的數
 *     注:此方法不對兩個數是否是數字進行校驗
 * @return String
 * */
public static String maxNum(String x, String y) {
    String max = "";

    if (x.length() > y.length()) {
        max = x;
    } else if (x.length() == y.length()) {
        for (int i = 1; i <= x.length(); i++) {
            if (numAt(x, i) != numAt(y, i)) {
                max = (numAt(x, i) > numAt(y, i)) ? x : y;
            } else if (i == x.length()) {
                max = x;
            }
        }
    } else if (x.length() < y.length()) {
        max = y;
    } else {
        return "ERROR";
    }
    return max;
}


/**
 * @param x y
 * @Desc 獲取兩個大數中較小的數
 *     注:此方法不對兩個數是否是數字進行校驗
 * @return String
 * */
public static String minNum(String x, String y) {
    String min = "";

    if (x.length() > y.length()) {
        min = y;
    } else if (x.length() == y.length()) {
        for (int i = 1; i <= x.length(); i++) {
            if (numAt(x, i) != numAt(y, i)) {
                min = (numAt(x, i) > numAt(y, i)) ? y : x;
            } else if (i == x.length()) {
                min = x;
            }
        }
    } else if (x.length() < y.length()) {
        min = x;
    } else {
        return "ERROR";
    }
    return min;
}


/**
 * @param x y
 * @Desc 大數x是否大于大數y
 * @return true/false
 * */
public static boolean forMax(String x, String y) {
    if (x.length() > y.length()) {
        return true;
    } else if (x.length() == y.length()) {
        for (int i = 1; i <= x.length(); i++) {
            if (numAt(x, i) != numAt(y, i)) {
                return (numAt(x, i) > numAt(y, i)) ? true : false;
            } else if (i == x.length()) {
                return true;
            }
        }
    } else if (x.length() < y.length()) {
        return false;
    } else {
        System.out.println("ERROR!!!");
    }
    return false;
}



/**
 * @param x
 * @Desc 判斷x是否是0或000……
 * @return true/false
 * */
public static boolean isZero(String x) {
    boolean flag = true;

    for (int i = 1; i <= x.length(); i++) {
        if (Tools.numAt(x, i) != 0) {
            return false;
        }
    }

    return flag;
}

}

工具類</code></pre>

七、鹵煮有話說

算法的實現上可以會多多少少存在點瑕疵,第一遍寫出來的代碼不是最好的,但我們要盡我們所能去優化和改善我們的代碼。

大家有什么想法都可以說出來,我們一起來探討大數的加減乘除,這樣讓這么有意義的事可以得到最后的解決方案。

想是一回事,做又是另一回事。讓我們腦洞大開,集思廣益一起來探討吧!!!

如果你覺得博文寫的不錯,就點下【 推薦一下 】或【 打賞 】 鹵煮一杯奶茶吧!!!

 

來自:http://www.cnblogs.com/JimLy-BUG/p/5965487.html

 

 本文由用戶 t3138011 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!