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

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;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值