编程题目:
拓展延伸:实现一个百亿级别的计算器。
示例代码:
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;
}
}