之所以會做用算法做大數的四則運算是因爲在參加藍橋杯比賽的時候被兩道大數題給坑慘了,因爲訓練的時候沒做過大數的題,在這上面吃了大虧,回來後痛定思痛,在網上找了一些方法,才發現有BigDecimal和BigInteger這兩個api類可以完美解決我的問題,我自然很好奇,於是在網上找到了這兩個類的源碼來看,結果越看越頭痛,整個源碼沒法在我心中有一個完整的結構,後來突然內心一動,爲什麼不自己來寫一個類似的api類呢?這個想法出來後就在心裏一發不可收拾,越加無法控制,說動就動。
類名:BigNum
功能:實現整數大數的五則運算,同時該類使用了Comparable接口,可以進行排序比較
屬性:
- NUM:存放表示大數的數組
- SIGN:存放大數的正負號
- DIGITS:存放大數的位數
- 所有屬性均爲final,不可修改
構造方法:
- BigNum(String number);使用傳入的字符串轉換成int型數組,會過濾掉開頭的零和非數字以及非正負號以外的其它所有符號,會忽略小數點及小數點後的所有字符,以最後一次出現的“-”“+”爲該大數符號,如未指定則默認爲“+”,如果字符串爲null或空將會拋出異常
- BigNum(int[] numArr, char sign);過濾傳入的int型數組的開頭的零,傳給NUM,如果數組中的數字超過一位將拆分爲多位數,將sign傳給SIGN,如果numArr爲空,或者sign不爲正負號將拋出異常
主要方法:
- add:加
- sub:減
- mul:乘
- div:除
- rem:取餘
- 以及一些具體做運算的方法,將在講到加減乘除這些方法時一併講
其它方法:
- public static int[] stringToIntArr(String s);將傳入的字符串轉換成int數組,該方法爲靜態方法,會過濾掉開頭的零和非數字,會忽略小數點及小數點後的所有字符。
- public static String intArrToString(int arr[]);將傳入的int數組轉換成字符串,該方法爲靜態方法。
- public int compareTo(BigNum num);比較兩個bignum對象的大小,包括符號,若當前對象小於,等於,大於num,則返回負整數,零,正整數
- private int ArrCompare(int a[], int b[]);大數數組同位數下比較大小,無符號,若a小於,等於,大於b,則返回負整數,零,正整數
- private int intArrCompaerTo(int numA[], int numB[]);判斷兩個大數數組的大小,無符號,若numA小於,等於,大於numB,則返回負整數,零,正整數
- public String toString();重寫toString,將NUM數組轉換成字符串,同時在前面加上符號,正號默認不加。
貼上代碼:
public class BigNum implements Comparable<BigNum> {
/**
* 表示大數的數組
*/
public final int NUM[];
/**
* 表示大數的正負號
*/
public final char SIGN;
/**
* 表示大數的位數
*/
public final int DIGITS;
public BigNum(String number) throws Exception {
if (number == null || number =="") {
throw new Exception("字符串爲空!");
}
char numChar[] = number.toCharArray();
char sign = 0;
//從左往右獲取輸入的值
for (int i = 0; i < numChar.length; i++) {
//設置大數正負號,以最後一個符號爲準
if (numChar[i] == 43 || numChar[i] == 45) {
sign = numChar[i];
}
}
if (sign == 0) {
sign = '+';
}
NUM = stringToIntArr(number);
SIGN = sign;
DIGITS = NUM.length;
}
public BigNum(int[] numArr, char sign) throws Exception {
if (numArr == null) {
throw new Exception("數組爲空!");
}
if (sign != '-' && sign != '+') {
throw new Exception("符號錯誤!非正負號!");
}
SIGN = sign;
NUM = stringToIntArr(intArrToString(numArr));
DIGITS = NUM.length;
}
public static int[] stringToIntArr(String s) {
char numChar[] = s.toCharArray();
StringBuilder sb = new StringBuilder();
boolean flag = true;
for (int i = 0; i < numChar.length; i++) {//從左往右獲取輸入的值
if (numChar[i] == 48 && flag) {//過濾掉開頭的零
continue;
}
if (numChar[i] == 46) {//忽略小數點'.'後的值
break;
}
if (numChar[i] > 47 && numChar[i] < 58) {//過濾掉非數字
flag = false;
sb.append(numChar[i]);
}
}
if (flag) {
sb.append("0");
}
char tempCharArr[] = sb.toString().toCharArray();
int num[] = new int[tempCharArr.length];
for (int j = 0; j < num.length; j++) {//將獲取到的數字從char轉換成int
num[j] = Integer.valueOf("" + tempCharArr[j]);
}
return num;
}
public static String intArrToString(int arr[]) {
StringBuilder sb = new StringBuilder(arr.length);
boolean flag = true;
for (int i : arr) {
if (i == 0 && flag) {//過濾掉開頭的零
continue;
}
flag = false;
sb.append(i);
}
if (flag) {
sb.append("0");
}
return sb.toString();
}
/**
* 比較兩個bignum對象的大小,包括符號。
* 若當前對象小於,等於,大於比較對象,則返回負整數,零,正整數
*
* @param num
* @return
*/
@Override
public int compareTo(BigNum num) {
if (this == num) {
return 0;
}
if (num == null) {
return 1;
}
if (SIGN < num.SIGN) {//當前對象正號 +號的ascll爲43,-號爲45
return 1;
} else if (SIGN > num.SIGN) {//當前對象負號
return -1;
} else {//同號
if (SIGN == '+') {//同正
if (DIGITS > num.DIGITS) {//位數大
return 1;
} else if (DIGITS < num.DIGITS) {//位數小
return -1;
} else {//位數相同
return ArrCompare(NUM, num.NUM);
}
} else {//同負,結果全部取反
if (DIGITS > num.DIGITS) {//位數大
return -1;
} else if (DIGITS < num.DIGITS) {//位數小
return 1;
} else {//位數相同
return -1 * ArrCompare(NUM, num.NUM);
}
}
}
}
/**
* 大數數組同位數下比較大小,無符號。
* 若a小於,等於,大於b,則返回負整數,零,正整數
*
* @param a
* @param b
* @return
*/
private int ArrCompare(int a[], int b[]) {
for (int i = 0; i < b.length; i++) {
if (a[i] > b[i]) {
return 1;
} else if (a[i] < b[i]) {
return -1;
}
}
return 0;
}
/**
* 判斷兩個大數數組的大小,無符號。
* 若當前數組小於,等於,大於比較數組,則返回負整數,零,正整數
*
* @param numArr
* @return
*/
private int intArrCompaerTo(int numA[], int numB[]) {
if (numA == numB) {
return 0;
}
if (numA.length > numB.length) {
return 1;
} else if (numA.length < numB.length) {
return -1;
} else {
return ArrCompare(numA, numB);
}
}
@Override
public String toString() {
return (SIGN == '+' ? "" : SIGN) + intArrToString(NUM);//忽略正號
}
最後,爲了避免太長,我將會寫成一個系列~~接下來將會對五則運算逐個詳解(其實是爲了多兩篇文章。。。)