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,整数,补开始的0
if (!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)
{
// 去除整数部分无效0
num1 = num1.replaceAll("^[+]?[0]*", ""); // +001.1, +1.1-->1.1 +0000.1,
// 0000.1->.1
num1 = num1.replaceAll("^[-][0]*", "-"); // -001.1, -1.1->-1.1
// -00.1->-.1
// 去除小数部分无效0
num1 = num1.replaceAll("[.]{1}[0]*$", ""); // 1.000, 1. -> 1
if (num1.indexOf('.') >= 0) // 避免将 1000 变为 1
{
num1 = num1.replaceAll("[0]*$", ""); // 1.10000 -> 1.1
}
// 将.1形式恢复为 0.1
num1 = num1.replaceAll("^[+]?[.]", "0.");
num1 = num1.replaceAll("^[-]?[.]", "-0.");
// 将"", "+", "-"恢复为0
num1 = 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;
// 移除小数点,即转换为整数后相乘,去掉无效0
num1 = formatNumber(num1.replace(".", ""));
num2 = formatNumber(num2.replace(".", ""));
// 对齐
StringBuffer buf1 = new StringBuffer(num1);
StringBuffer buf2 = new StringBuffer(num2);
alignment(buf1, buf2, false);
// 相乘后的缓存结果List
List<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个0
for (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
{
// 长度小于小数位数,前面补0
StringBuffer 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;
}
}
支持正负号及小数的大数加减及乘法计算
最新推荐文章于 2021-05-17 13:53:26 发布