當簡單的計算遇上了大數,其實大數運算也很簡單
一、說三道四
用代碼實現簡單的加減乘除運算會不會?只要你是個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