編程題目:
拓展延伸:實現一個百億級別的計算器。
示例代碼:
package program.calculation.exercise70;
/**
* 拓展延伸:實現一個百億級別的計算器。
*/
public class MyBigCalculator {
public static void main(String[] args) {
String str1 = "123789965783241232323512323676678";
String str2 = "23245235435436807768829454365465889";
//String str1 = "0000000000000100000000000000000000000000000000000002";
//String str2 = "000000000000050000000000000000000000000000000000000";
//String str1 = "2433456789";
//String str2 = "4345678";
System.out.println("兩數之和:"+add(str1, str2));
System.out.println("兩數之差:"+subtract(str1, str2));
System.out.println("兩數之積:"+multiply(str1, str2));
System.out.println("兩數之商:"+divide(str1, str2));
System.out.println("兩數之餘:"+remainder(str1, str2));
}
//相加
private static String add(String str1,String str2){
StringBuffer res = new StringBuffer(); //和(summary)
//根據數字字符串的正負號,決定調用不同的方法
if(str1.contains("-") && str2.contains("-")){
str1 = str1.replace("-", "");
str2 = str2.replace("-", "");
return "-"+add(str1, str2);
}else if((!str1.contains("-") && str2.contains("-"))){
return subtract(str1,str2.replace("-", ""));
}else if((str1.contains("-") && !str2.contains("-"))){
return subtract(str2,str1.replace("-", ""));
}
//去除數字字符串前面的0,但注意應先去除正負號
String s1 = str1.replaceAll("^0*", "");
String s2 = str2.replaceAll("^0*", "");
//如果兩數均爲0,則和爲0,注意:此時0已被去除,爲空白字符串
if("".equals(s1) && "".equals(s2)){
return "0";
}
//將兩個數字的位數設爲相同,不同的前面補0
int len = Math.abs(s1.length()-s2.length());//返回兩數相減的絕對值
if(s1.length() > s2.length()){
s2 = makeSameFigure(s2,len);
}else{
s1 = makeSameFigure(s1,len);
}
//兩數的對應位數依次相加,大於9需要向前進位
int n = 0; //需要進位的個數
for(int i=s1.length()-1;i>=0;i--){
//通過對應位數的數字字符的ASCII碼相減獲取數字
int temp = (s1.charAt(i)-'0')+(s2.charAt(i)-'0')+n;//如果需要進位,則加上進位的個數
if(i == 0){ //所有位數數字相加結束
//temp%10:本位數字,temp/10:進位數字,如果爲0,則不進位
res.append(temp%10).append(temp/10==0?"":temp/10);//注意:此處從前往後添加,輸出時倒序輸出
}else{
res.append(temp%10); //將本位數字添加進結果中
n = temp/10; //記錄進位的個數
}
}
//去除首位數字0,並將StringBuffer類型的res轉換爲String類型,注意:輸出需要倒序
return kickFirstZero(String.valueOf(res.reverse()));
}
//相減
private static String subtract(String str1,String str2){
boolean flag = false;//判斷被減數與減數的大小,false:被減數大於減數
StringBuffer res = new StringBuffer(); //差(difference)
//根據數字字符串的正負號,決定調用不同的方法
if(str1.contains("-") && str2.contains("-")){
return subtract(str2.replace("-", ""),str1.replace("-", ""));
}else if((!str1.contains("-") && str2.contains("-"))){
return add(str1,str2.replace("-", ""));
}else if((str1.contains("-") && !str2.contains("-"))){
return "-"+add(str2,str1.replace("-", ""));
}
//去除數字字符串前面的0,但注意應先去除正負號
String s1 = str1.replaceAll("^0*", "");
String s2 = str2.replaceAll("^0*", "");
//如果兩數相等,差爲0,包括兩數均爲0的情況(其實此時爲空白字符串,0已經被去除)
if(s1.equals(s2)){
return "0";
}
//如果被減數小於減數,則交換,同時將flag置爲true
if(!isBigger(s1,s2)){
flag = true;
String temp = s1;
s1 = s2;
s2 = temp;
}
//將兩個數字的位數設爲相同,不同的前面補0
s2 = makeSameFigure( s2,s1.length()-s2.length());
//兩數的對應位數依次相減,不夠減需要向前借位
int n = 0; //需要借位的個數
for(int i=s1.length()-1;i>=0;i--){
//通過對應位數的數字字符的ASCII碼相減獲取數字
int temp = (s1.charAt(i)-'0')-(s2.charAt(i)-'0')-n;//再減去借位的個數
if(i == 0){ //所有位數數字相減結束
//如果最後位數數字爲0,則轉換爲空白字符串
res.append(temp==0?"":temp);//注意:此處是從後往前添加的,輸出需要倒序
}else{
//如果位數數字大於等於0,則添加進結果,如果小於0,則需要借位+10,再相減
res.append(temp>=0?temp:temp+10);
n = temp>=0?0:1; //記錄借位的個數
}
}
//去除首位數字0,並將StringBuffer類型的res轉換爲String類型,注意:輸出需要倒序
String s = kickFirstZero(String.valueOf(res.reverse()));
//如果flag=true,說明被減數小於減數,結果應加上負號-,
return flag?"-"+s:s;
}
//相乘
private static String multiply(String str1,String str2){
String res = ""; //積(product)
//判斷積(product)的正負號
int p = 0; //若p爲偶數,積爲正數,若p爲奇數,積爲負數
if(str1.contains("-")){
str1 = str1.replace("-", "");
p++;
}
if(str2.contains("-")){
str2 = str2.replace("-", "");
p++;
}
//去除數字字符串前面的0,但注意應先去除正負號
String s1 = str1.replaceAll("^0*", "");
String s2 = str2.replaceAll("^0*", "");
//如果兩數有一個爲0,則結果爲0,注意:0已經被去除,此處爲空白字符串
if("".equals(s1) || "".equals(s2)){
return "0";
}
//根據乘法的運算規則:被乘數分別乘以乘數的位數數字,然後再相加
for(int i=s2.length()-1;i>=0;i--){ //乘數的位數
//被乘數乘以乘數的位數數字n,其實也就是本身自加n次
for(int j=0;j<s2.charAt(i)-'0';j++){ //通過ASCII碼相減獲取位數數字
res = add(res,s1); //結果相加
}
s1 += "0"; //被乘數每乘以完乘數一個位數數字後,應進位,擴大10倍,字符串直接加0即可
}
//如果負號爲奇數個,即c==1,則結果應爲負數,加上"-"
return p==1?"-"+res:res;
}
//相除
private static String divide(String str1,String str2){
String res = ""; //商(quotient)
//判斷商的正負號
int q = 0; //若q爲偶數,商爲正數,若q爲奇數,商爲負數
if(str1.contains("-")){
str1 = str1.replace("-", "");
q++;
}
if(str2.contains("-")){
str2 = str2.replace("-", "");
q++;
}
//去除數字字符串前面的0,但注意應先去除正負號
String s1 = str1.replaceAll("^0*", "");
String s2 = str2.replaceAll("^0*", "");
//如果除數爲0,表達式錯誤,注意:0已經被去除,此處爲空白字符串
if("".equals(s2)){
return "ERROR";
}
//如果被除數絕對值小於除數絕對值,則商爲0,或者被除數爲0,注意:0已被去除,此處爲空白字符串
if(!isBigger(s1,s2) || "0".equals(s1)){
return "0";
}
//如果被除數絕對值等於除數絕對值,則商絕對值爲1
if(s1.equals(s2)){
res = "1"; //此處賦值給res,因爲要添加正負號
}else{ //主要處理被除數大於除數的情況
//如果被除數的首位數字大於等於除數首位數字,則給被除數補一個零
//此種情況如果不給被除數補一個零,則商會少最後一位數
//原因:運行下面代碼將位數置爲相等後,此種情況下,其實被除數相當於少了一位數
if(s1.charAt(0) >= s2.charAt(0)){
s1 += "0";
}
//主要處理被除數位數大於除數位數的情況
for (int n=s1.length()-s2.length();n>0;n--) { //n是s1與s2的位數差
//除數補零操作,使除數的位數與被除數的位數相等
while(s1.length() > s2.length()){
s2 += "0";
}
//如果補零後被除數小於除數,則給被除數補一個零,否則進行下一步運算
if (!isBigger(s1, s2)) {
s1 += "0";
}
//循環找出 除數*i(i數0~9之間的數)的結果不大於被除數的最大i值,找到的i即爲商的位數值
for (int i=9;i>=0;i--) { //注意此處應倒序,因爲循環找到不大於被除數的最大i值
String temp = multiply(s2, String.valueOf(i));
if (isBigger(s1, temp)) { //s1大於temp說明此時找到的i即爲商的位數值
s1 = subtract(s1, temp); //本次循環後的餘數,作爲下一次循環的被除數
res += i; //將i添加到結果上
break; //結束本次循環,開始執行下次循環
}
}
}
}
//如果負號爲奇數個,即c==1,則結果應爲負數,加上"-"
return q==1?"-"+res:res;
}
//取餘
private static String remainder(String str1,String str2){
//第一種方式:取餘運算:被除數-(商*除數)=餘數,該方法比較取巧
/*String quotient = divide(str1, str2); //獲取兩數之商
String product = multiply(quotient, str2); //獲取商和除數之積
String difference = subtract(str1, product); //獲取餘數
return difference;*/
//第二種方式:等同於除法,只不過進行了餘數判斷以及記錄除數補0的次數
String res = ""; //商(quotient)
String rem = ""; //餘數(remainder)
//判斷商(quotient)和餘數(remainder)的正負號
int q = 0; //若q爲偶數,商爲正數,若q爲奇數,商爲負數
int r = 0; //若r爲偶數,餘數爲正數,若r爲奇數,餘數爲負數,根據被除數的正負號判斷
if(str1.contains("-")){
str1 = str1.replace("-", "");
q++;
r++;
}
if(str2.contains("-")){
str2 = str2.replace("-", "");
q++;
}
//去除數字字符串前面的0,但注意應先去除正負號
String s1 = str1.replaceAll("^0*", "");
String s2 = str2.replaceAll("^0*", "");
//如果除數爲0,表達式錯誤,注意:0已經被去除,此處爲空白字符串
if("".equals(s2)){
return "ERROR";
}
//如果被除數絕對值小於除數絕對值,則餘數爲被除數本身
if(!isBigger(s1,s2)){
rem = s1; //此處賦值給rem,因爲要添加正負號
}
//記錄除數在下面代碼中補0的次數
int count = 0; //除數每補一次0,就會導致餘數結尾多一個0
//如果被除數絕對值等於除數絕對值,則餘數爲0,或者被除數爲0,注意:0已被去除,此處爲空白字符串
if(s1.equals(s2) || "".equals(s1)){
return "0";
}else{ //主要處理被除數大於除數的情況
//如果被除數的首位數字大於等於除數首位數字,則給被除數補一個零
//此種情況如果不給被除數補一個零,則商會少最後一位數
//原因:運行下面代碼將位數置爲相等後,此種情況下,其實被除數相當於少了一位數
if(s1.charAt(0) >= s2.charAt(0)){
s1 += "0";
}
//主要處理被除數位數大於除數位數的情況
for (int n=s1.length()-s2.length();n>0;n--) { //n是s1與s2的位數差
//除數補零操作,使除數的位數與被除數的位數相等
while(s1.length() > s2.length()){
s2 += "0";
count++; //除數每補一次0,count就加1
}
//如果補零後被除數小於除數,則給被除數補一個零,否則進行下一步運算
if (!isBigger(s1, s2)) {
s1 += "0";
}
//循環找出 除數*i(i數0~9之間的數)的結果不大於被除數的最大i值,找到的i即爲商的位數值
for (int i=9;i>=0;i--) { //注意此處應倒序,因爲循環找到不大於被除數的最大i值
String temp = multiply(s2, String.valueOf(i));
if (isBigger(s1, temp)) { //s1大於temp說明此時找到的i即爲商的位數值
s1 = subtract(s1, temp); //本次循環後的餘數,作爲下一次循環的被除數
res += i; //將i添加到結果上
break; //結束本次循環,開始執行下次循環
}
}
}
}
//如果負號爲奇數個,即q==1,則結果應爲負數,加上"-"
res = q==1?"-"+res:res; //商
if("0".equals(s1)){ //如果s1爲0,則不再去除多出的0
rem = s1;
}else{
rem = s1.substring(0,s1.length()-count);//去除餘數後面多出的0
}
//如果被除數爲負數,即r==1,則結果應爲負數,加上"-",注意:如果餘數爲0,就不需要再加上負號"-"
return rem=="0"?rem:r==1?"-"+rem:rem;
}
//判斷大小
private static boolean isBigger(String str1,String str2){
//去除數字字符串前面的正負號和0,但注意應先去除正負號
String s1 = str1.replace("-", "").replaceAll("^0*", "");
String s2 = str2.replace("-", "").replaceAll("^0*", "");
if(s1.length() > s2.length()){
return true;
}else if(s1.length() < s2.length()){
return false;
}else if(s1.length() == s2.length()){
for(int i=0;i<s1.length();i++){
if(s1.charAt(i) < s2.charAt(i)){
return false;
}else if(s1.charAt(i) > s2.charAt(i)){
return true;
}
}
}
return true;
}
//將兩個數字位數設爲相等
private static String makeSameFigure(String s,int len){
StringBuffer sb = new StringBuffer();
for(int i=0;i<len;i++){
sb.append("0");
}
s = String.valueOf(sb.append(s));
return s;
}
//去除首位數字0
private static String kickFirstZero(String s){
while(s.length() > 1){
if('0' == s.charAt(0)){
//substring(0,index)表示獲取下標爲0-index(不包括)的元素
s = s.substring(1); //注意:substring(index)表示去除下標爲index的元素
}else{
break;
}
}
return s;
}
}