紅包金額均分實現

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);
	}
}
相關文章
相關標籤/搜索