1、說三道四算法
用代碼實現簡單的加減乘除運算會不會?只要你是個coder,我想這個答案都是確定的吧!ide
可是,今天我想說的是,當咱們的運算遇到了大數,用本來的int、long、float、double數值類型工具
都沒法表示出來的時候,大家想過該若是解決這一類型的問題了嗎?優化
在這,大家能夠先不用看滷煮擼的代碼,想一想若是本身遇到這個問題,該若是解決,也許你的想法spa
很新穎,思路以及在算法的實現上更清晰。但願可以在廣大的博友的集思廣益下,大數的運算可以有code
一套更好的解決方案。不說了,我們先擼代碼吧。畢竟這纔是主題!!!blog
2、大數運算之加法運算ci
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")); } }
思路分析:rem
大數的相加主要是經過字符串的相加來實現的。兩個大數相加,找出位數較大的那個大數獲取對應的長度,字符串
而後對較小的那個數進行左補0直至長度和較大的那個數的位數同樣,最後循環累加兩個大數的每一位的數值,
遇到須要進位的須要設一個標識位標識。
3、大數運算之減法運算
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")); } }
思路分析:
大數相減在實現上和大數相加殊途同歸,也是經過循環遍歷大數的每一位,對其進行數值相減,在遇到須要借位的數值,
設立一個標識位進行標識。當遇到被減數比減數小的時候,先用減數減去被減數,用標識位標識被減數比減數小,最後結果
根據標識變量判斷是否須要在結果上加上"-"。
4、大數運算之乘法運算
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")); } }
思路分析:
大數相乘在算法的實現上我的表示有點不太滿意,雖然實現了功能,但仍是以爲代碼的實現上和思路都很挫。
乘法的最終思路就是多個數值的加法運算。因此大數的乘法就是多個大數的加法運算。可是遇到兩個數值都是大數的狀況下,
運行速度會很是的慢。
5、大數運算之除法運算
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")); } }
思路分析:
除法運算的實質也就是減法,讓被除數一直減去除數,直到減不動了爲止,統計下減了多少次除數,這個值就是商咯。
可是存在的問題仍是和大數的乘法是同樣的,有待優化。
6、大數運算之工具類
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; } }
7、滷煮有話說
也許擼主的代碼算法的實現上可能會多多少少存在點瑕疵,第一遍寫出來的代碼不是最好的,但咱們要盡咱們所能去
優化和改善咱們的代碼。你們有什麼想法均可以說出來,咱們一塊兒來探討大數的加減乘除,讓這麼有意義的事能夠獲得
最優質的解決方案。在求知的路上,咱們不怕批評,不怕失敗,更不要在乎別人的嘲笑,一步一步攀巖,咱們終將登頂。
想是一回事,作又是另外一回事。讓咱們腦洞大開,集思廣益一塊兒來探討吧!!!
若是你以爲博文寫的不錯,就點下【推薦一下】或【打賞】滷煮一杯奶茶吧!!!