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