红包金额均分实现

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * 红包均分
 * 
 * @author liyulin
 * @version 1.0 2017年3月31日 上午11:28:35
 */
public final class MoneyUtil {

	/**
	 * 红包金额根据所占总金额比例均分
	 * 
	 * @param totalAmt 总金额(单位:分),为null时,会在内部计算其值
	 * @param subAmts 全部资金额(单位:分)
	 * @param totalHbAmt 红包总金额(单位:分)
	 * @return 返回全部均分的金额(单位:分)
	 */
	public static final List<BigDecimal> getSubMoney(BigDecimal totalAmt,
			List<BigDecimal> subAmts, BigDecimal totalHbAmt) {
		if (totalAmt == null) {
			totalAmt = BigDecimal.ZERO;
			for (BigDecimal subAmt : subAmts) {
				totalAmt = totalAmt.add(subAmt);
			}
		}

		/** 由于计算时,最后一个的值为总红包金额减去其他红包总额,若是最后的帐单金额为0,会出现红包金额为负数的状况 */
		int dealSize = getDealSubAmtMaxIndex(subAmts);// 从最后一个开始倒序,实付为大于0的索引

		/** 最后实付金额(连续)为非0的处理 */
		List<BigDecimal> subHbAmts = dealNonNegative(dealSize, totalAmt, subAmts, totalHbAmt);
		
		/** 最后实付金额(连续)为0的处理 */
		for (int i = dealSize + 1; i < subAmts.size(); i++) {
			subHbAmts.add(BigDecimal.ZERO);
		}

		/** 分配的最后一个红包为负数的处理 */
		dealLastNegative(dealSize, subHbAmts, subAmts);

		return subHbAmts;
	}
	
	/**
	 * 非0实付处理
	 * @param dealSize
	 * @param totalAmt
	 * @param subAmts
	 * @param totalHbAmt
	 * @return
	 */
	public static final List<BigDecimal> dealNonNegative(int dealSize,
			BigDecimal totalAmt, List<BigDecimal> subAmts, BigDecimal totalHbAmt) {
		List<BigDecimal> subHbAmts = new ArrayList<BigDecimal>();
		BigDecimal otherTotalAmt = BigDecimal.ZERO;
		for (int i = 0; i <= dealSize; i++) {
			BigDecimal subHbAmt = null;
			if (i < dealSize) {
				BigDecimal subAmt = subAmts.get(i);

				subHbAmt = div(subAmt.multiply(totalHbAmt), totalAmt);
				BigDecimal subUpHbAmt = subHbAmt.setScale(0, RoundingMode.UP);
				if (subUpHbAmt.compareTo(subAmt) < 0) {
					subHbAmt = subUpHbAmt;
				} else {
					subHbAmt = subAmt;
				}

				otherTotalAmt = otherTotalAmt.add(subHbAmt);
			} else {// 最后一个
				subHbAmt = totalHbAmt.subtract(otherTotalAmt);
			}

			subHbAmts.add(subHbAmt);
		}

		return subHbAmts;
	}
	
	/**
	 * 获取处理的最后一个子账单的索引
	 * @param subAmts
	 * @return
	 */
	public static final int getDealSubAmtMaxIndex(List<BigDecimal> subAmts){
		int dealSize = 0;// 从最后一个开始倒叙,实付为大于0的索引
		/** 由于计算时,最后一个的值为总红包金额减去其他红包总额,若是最后的帐单金额为0,会出现红包金额为负数的状况 */
		for (int i = subAmts.size() - 1; i >= 0; i--) {
			BigDecimal subAmtTmp = subAmts.get(i);
			if (subAmtTmp.compareTo(BigDecimal.ZERO) != 0) {
				dealSize = i;
				break;
			}
		}
		return dealSize;
	}
	
	/**
	 * 分配的最后一个红包为负数的处理
	 * @param dealSize
	 * @param subHbAmts
	 * @param subAmts
	 */
	public static final void dealLastNegative(int dealSize, List<BigDecimal> subHbAmts, List<BigDecimal> subAmts){
		if(subHbAmts.get(dealSize).compareTo(BigDecimal.ZERO) < 0){
			long balanceAmt = Math.abs(subHbAmts.get(dealSize).longValue());
			subHbAmts.set(dealSize, BigDecimal.ZERO);
			for (int i = 0; i < dealSize; i++) {
				long partBalanceAmt = subAmts.get(i).longValue() - subHbAmts.get(i).longValue();
				if (partBalanceAmt > 0) {
					if (partBalanceAmt >= balanceAmt) {
						subHbAmts.set(i, subHbAmts.get(i).subtract(BigDecimal.valueOf(balanceAmt)));
						break;
					} else {
						subHbAmts.set(i, subHbAmts.get(i).subtract(BigDecimal.valueOf(partBalanceAmt)));
						balanceAmt -= partBalanceAmt;
						if (balanceAmt == 0) {
							break;
						}
					}
				}
			}
		}
	}
	
	public static final BigDecimal div(BigDecimal num1, BigDecimal num2) {
		if (num1 == null || num2 == null) {
			return null;
		}
		return num1.divide(num2, 4, RoundingMode.DOWN);
	}

	public static void main(String[] args) {
		List<BigDecimal> subAmts = new ArrayList<BigDecimal>();

		subAmts.add(BigDecimal.valueOf(48));
		subAmts.add(BigDecimal.valueOf(122));
		subAmts.add(BigDecimal.valueOf(196));
		subAmts.add(BigDecimal.valueOf(10));

		BigDecimal totalHbAmt = BigDecimal.valueOf(8);

		List<BigDecimal> allSubHbAmts = getSubMoney(null, subAmts, totalHbAmt);
		System.err.println(allSubHbAmts);
	}
}
相关文章
相关标签/搜索