支持正负号及小数的大数加减及乘法计算

来源:互联网 发布:网络说唱歌手 编辑:程序博客网 时间:2024/05/01 05:03
package largenumber;import java.util.ArrayList;import java.util.List;import java.util.regex.Matcher;import java.util.regex.Pattern;public class LargeNumberCal{/** * 大数相加,支持小数,正负号 *  * @param num1 * @param num2 * @return */public static String add(String num1, String num2){long startTime = System.currentTimeMillis();String result = doAdd(num1, num2);System.out.println(String.format("加法运算时间为:%d ms", System.currentTimeMillis() - startTime));return result;}private static String doAdd(String num1, String num2){num1 = validationNum(num1);num2 = validationNum(num2);if (num1 == null || num2 == null){return null;}if ("0".equals(num1)){return num2;}if ("0".equals(num2)){return num1;}// 是否为正数boolean positiveOfNum1 = (num1.charAt(0) != '-');boolean positiveOfNum2 = (num2.charAt(0) != '-');if (positiveOfNum1 && positiveOfNum2){// 全为正的话,直接处理return doAddOrSubTwoLargeNum(num1, num2, CalcEnum.ADD);}else if (!positiveOfNum1 && !positiveOfNum2){// 全负的话,相反相加结果再相反return negate(add(negate(num1), negate(num2)));}else if (positiveOfNum1 && !positiveOfNum2){// num1正数,num2负数,减法运算return sub(num1, negate(num2));}else{// num1负数,num2正数,减法运算return sub(num2, negate(num1));}}/** * 两个不包含小数点,且已对齐的数值相加减 *  * @param num1 * @param num2 * @param plusNum * @param resultBuf * @return */private static int addOrSubAlignmentInteger(StringBuffer num1, StringBuffer num2, int plusNum, StringBuffer resultBuf, CalcEnum calcType){char[] decimalChArrayNum1 = num1.toString().toCharArray();char[] decimalChArrayNum2 = num2.toString().toCharArray();for (int i = decimalChArrayNum1.length - 1; i >= 0; --i){plusNum = addOrSubOrMulTwoChar(decimalChArrayNum1[i], decimalChArrayNum2[i], plusNum, resultBuf, calcType);}// 注意,在上面的循环中是将低位保存在前的(提高append效率),此处要将结果取反resultBuf.reverse();return plusNum;}private static void alignment(StringBuffer num1, StringBuffer num2, boolean isDecimal){if (num1.length() == num2.length()){return;}else if (num1.length() < num2.length()){// 小数,补末尾的0,整数,补开始的0if (!isDecimal){num1.reverse();}int needAddZeroNum = num2.length() - num1.length();for (int i = 0; i < needAddZeroNum; i++){num1.append("0");}if (!isDecimal){num1.reverse();}}else{alignment(num2, num1, isDecimal);}}/** * 相反运算 *  * @param num1 * @return */private static String negate(String num1){if ("0".equals(num1)){return num1;}else if (num1.charAt(0) == '-'){return num1.replace("-", "");}else if (num1.charAt(0) == '+'){return num1.replace("+", "-");}else{return "-" + num1;}}/** * 数值有效性校验并格式化: 符号+有效数字,有多余的0, 如+11.1, 11.1, -11.1 * 格式化包括去掉整數部份首部無效0,小數部份尾部無效0 *  * @param num1 * @return */private static String validationNum(String num1){String regex = "(^[+-]?\\d*[.]?\\d*$)";Pattern pattern = Pattern.compile(regex);Matcher match = pattern.matcher(num1);if (match.matches()){return formatNumber(num1);}return null;}private static String formatNumber(String num1){// 去除整数部分无效0num1 = num1.replaceAll("^[+]?[0]*", ""); // +001.1, +1.1-->1.1 +0000.1,// 0000.1->.1num1 = num1.replaceAll("^[-][0]*", "-"); // -001.1, -1.1->-1.1// -00.1->-.1// 去除小数部分无效0num1 = num1.replaceAll("[.]{1}[0]*$", ""); // 1.000, 1. -> 1if (num1.indexOf('.') >= 0) // 避免将 1000 变为 1{num1 = num1.replaceAll("[0]*$", ""); // 1.10000 -> 1.1}// 将.1形式恢复为 0.1num1 = num1.replaceAll("^[+]?[.]", "0.");num1 = num1.replaceAll("^[-]?[.]", "-0.");// 将"", "+", "-"恢复为0num1 = num1.replaceAll("^[+-]?$", "0");return num1;}public static String mul(String num1, String num2){long startTime = System.currentTimeMillis();String result = doMul(num1, num2);System.out.println(String.format("乘法运算时间为:%d ms", System.currentTimeMillis() - startTime));return result;}/** * 大数相乘 *  * @param num1 * @param num2 * @return */private static String doMul(String num1, String num2){num1 = validationNum(num1);num2 = validationNum(num2);if (num1 == null || num2 == null){return null;}if ("0".equals(num1) || "0".equals(num2)){return "0";}if ("1".equals(num1)){return num2;}if ("1".equals(num2)){return num1;}boolean positiveOfNum1 = (num1.charAt(0) != '-');boolean positiveOfNum2 = (num2.charAt(0) != '-');if (positiveOfNum1 && positiveOfNum2){// 小数点位数int decimalNum1 = num1.indexOf('.') > 0 ? num1.length() - 1 - num1.indexOf('.') : 0;int decimalNum2 = num2.indexOf('.') > 0 ? num2.length() - 1 - num2.indexOf('.') : 0;// 移除小数点,即转换为整数后相乘,去掉无效0num1 = formatNumber(num1.replace(".", ""));num2 = formatNumber(num2.replace(".", ""));// 对齐StringBuffer buf1 = new StringBuffer(num1);StringBuffer buf2 = new StringBuffer(num2);alignment(buf1, buf2, false);// 相乘后的缓存结果ListList<String> restList = new ArrayList<String>();char[] num1ChArray = buf1.reverse().toString().toCharArray();char[] num2ChArray = buf2.reverse().toString().toCharArray();for (int i = 0; i < num2ChArray.length; ++i){StringBuffer tmpBuffer = new StringBuffer();// 第n位参与运算时先填充n-1个0for (int j = 0; j < i; j++){tmpBuffer.append("0");}// 进位标示int plusNum = 0;for (int j = 0; j < num1ChArray.length; j++){plusNum = addOrSubOrMulTwoChar(num2ChArray[i], num1ChArray[j], plusNum, tmpBuffer, CalcEnum.MUL);}if (plusNum > 0){tmpBuffer.append(plusNum);}restList.add(tmpBuffer.reverse().toString());}// 累加乘法中间结果项String result = restList.get(0);for (int i = 1; i < restList.size(); i++){result = doAdd(result, restList.get(i));}// 处理小数点int totalDecimalNum = decimalNum1 + decimalNum2;if (totalDecimalNum > 0){if (result.length() > totalDecimalNum){// 长度大于小数位数,中间插入小数StringBuffer resultBuf = new StringBuffer(result);resultBuf.insert(result.length() - totalDecimalNum, ".");return formatNumber(resultBuf.toString());}else{// 长度小于小数位数,前面补0StringBuffer resultBuf = new StringBuffer(result);resultBuf.reverse();for (int i = resultBuf.length(); i < totalDecimalNum; i++){resultBuf.append(0);}resultBuf.append(".0");resultBuf.reverse();return formatNumber(resultBuf.toString());}}else{return result;}}else if (!positiveOfNum1 && !positiveOfNum2){return mul(negate(num1), negate(num2));}else if (positiveOfNum1 && !positiveOfNum2){return negate(mul(num1, negate(num2)));}else{return negate(mul(negate(num1), num2));}}/** * 大数相减 *  * @param num1 * @param num2 * @return */public static String sub(String num1, String num2){num1 = validationNum(num1);num2 = validationNum(num2);if (num1 == null || num2 == null){return null;}if ("0".equals(num1)){return negate(num2);}if ("0".equals(num2)){return num1;}// 是否为正数boolean positiveOfNum1 = (num1.charAt(0) != '-');boolean positiveOfNum2 = (num2.charAt(0) != '-');// 正数 - 正数if (positiveOfNum1 && positiveOfNum2){// 先比较数值大小,if (comparePositiveLargerNum(num1, num2) == 0){return "0";}else if (comparePositiveLargerNum(num1, num2) < 0){return negate(sub(num2, num1));}else{return doAddOrSubTwoLargeNum(num1, num2, CalcEnum.SUB);}}// 正数 - 负数 = 正数 + 负数绝对值else if (positiveOfNum1 && !positiveOfNum2){return doAdd(num1, negate(num2));}// 负数 - 正数 = -( 负数绝对值 + 正数)else if (!positiveOfNum1 && positiveOfNum2){return negate(doAdd(negate(num1), num1));}else{return sub(negate(num2), negate(num1));}}/** * 两个正的大数加减,如果是减,其值大的数在前 * @param num1 * @param num2 * @param calcType * @return */private static String doAddOrSubTwoLargeNum(String num1, String num2, CalcEnum calcType){// 将数值分解为整数及小数部分String[] split = num1.split("\\.");StringBuffer integerOfNum1 = new StringBuffer(split[0]);StringBuffer decimalsOfNum1 = new StringBuffer((split.length > 1) ? split[1] : "0");String[] split2 = num2.split("\\.");StringBuffer integerOfNum2 = new StringBuffer(split2[0]);StringBuffer decimalsOfNum2 = new StringBuffer((split2.length > 1) ? split2[1] : "0");// 先数位补0对齐alignment(integerOfNum1, integerOfNum2, false);alignment(decimalsOfNum1, decimalsOfNum2, true);// 是否需要进位标示int plusNum = 0;// 先计算小数部分StringBuffer decimalPartResult = new StringBuffer();plusNum = addOrSubAlignmentInteger(decimalsOfNum1, decimalsOfNum2, plusNum, decimalPartResult, calcType);// 再计算整数部分StringBuffer integerPartResult = new StringBuffer();plusNum = addOrSubAlignmentInteger(integerOfNum1, integerOfNum2, plusNum, integerPartResult, calcType);// 將最后的进位补上if (plusNum > 0){integerPartResult.insert(0, plusNum);}String result = integerPartResult.toString() + "." + decimalPartResult.toString();return formatNumber(result);}/** * 比较两个正的大数数值大小 * @param num1 * @param num2 * @return */private static int comparePositiveLargerNum(String num1, String num2){String[] split = num1.split("\\.");String integerOfNum1 = split[0];String decimalsOfNum1 = (split.length > 1) ? split[1] : "0";String[] split2 = num2.split("\\.");String integerOfNum2 = split2[0];String decimalsOfNum2 = (split2.length > 1) ? split2[1] : "0";// 先通过长度进行判断以获取较优性能if (integerOfNum1.length()>integerOfNum2.length()){return 1;}else if (integerOfNum1.length()<integerOfNum2.length()){return -1;}else{if (integerOfNum1.compareTo(integerOfNum2)!=0){return integerOfNum1.compareTo(integerOfNum2);}else{// 整数部分相等,需要比较小数部分int minSize = decimalsOfNum1.length()<decimalsOfNum2.length()? decimalsOfNum1.length():decimalsOfNum2.length();for (int i = 0; i < minSize; i++){if (decimalsOfNum1.charAt(i)-decimalsOfNum2.charAt(i)!=0){return decimalsOfNum1.charAt(i)-decimalsOfNum2.charAt(i);}else{continue;}}// 循环完成后,看谁还有没比较完的值,谁就大if (decimalsOfNum1.length()>minSize){return 1;}else if (decimalsOfNum2.length()>minSize){return -1;}else{return 0;}}}}/** * 对两个数字进行加或乘,同时传入历史进位标示 *  * @param c * @param d * @param plusNum * @param result * @param calcEnum * @return */private static int addOrSubOrMulTwoChar(char c, char d, int plusNum, StringBuffer result, CalcEnum calcEnum){int num1 = c - '0';int num2 = d - '0';int sum = 0;switch (calcEnum){case ADD:sum = num1 + num2 + plusNum;break;case SUB:sum = num1 - num2 + plusNum;break;case MUL:sum = num1 * num2 + plusNum;break;default:break;}int newPlusNum = 0;if (sum >= 10){newPlusNum = sum / 10;sum %= 10;}else if (sum<0){newPlusNum = -1;sum += 10;}result.append(sum);return newPlusNum;}}

原创粉丝点击