import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
/**
* 红包生成二倍均值法、平均分配法
*/
public class RedPacketUtil2 {
/**
* 生成红包最大值 200人民币
*/
private static BigDecimal MAX_MONEY =new BigDecimal("200");
/**
* 生成红包最小值 1分
*/
private static BigDecimal MIN_MONEY = new BigDecimal("0.01");
//百
final static BigDecimal hundred = new BigDecimal("100");
//2倍
final static BigDecimal two = new BigDecimal("2");
final static Random random = new Random();
public static void setMaxMoney(BigDecimal maxMoney) {
MAX_MONEY = maxMoney;
}
public static void setMinMoney(BigDecimal minMoney) {
MIN_MONEY = minMoney;
}
public static void main(String[] args) {
setMaxMoney(new BigDecimal("200"));
setMinMoney(new BigDecimal("0.01"));
BigDecimal amount = new BigDecimal("20000");
List<BigDecimal> moneys = splitRedPacket(amount, new BigDecimal("30"));
BigDecimal sum = BigDecimal.ZERO;
for (BigDecimal money : moneys) {
System.out.println("金额"+money);
sum=sum.add(money);
}
System.out.println("总金额为:"+amount+",生成红包的总金额为:"+sum+"剩余金额:"+amount.subtract(sum));
}
/**
*
* @param amount 总金额
* @param num 红包个数
*/
public static List<BigDecimal> splitRedPacket(BigDecimal amount, BigDecimal num){
List<BigDecimal> moneys = new ArrayList<>();
//remain剩余红包金额=总金额-(最小金额*个数)
//这里是为了保证每个人都能拿到至少最小金额数,然后拿剩下的来随机分配
BigDecimal remain = amount.subtract(MIN_MONEY.multiply(num));
//计算出最大红包
BigDecimal max = amount.divide(num,2, RoundingMode.FLOOR).multiply(two);
//如果计算出的最大红包大于设置的最大红包则最大红包=设置的最大红包
max = max .compareTo(MAX_MONEY)>0 ? MAX_MONEY : max;
//红包金额
BigDecimal redPeck = new BigDecimal("0");
for (int i = 0; i < num.intValue(); i++) {
//如果是最后一个,
if(i == num.intValue() -1){
//如果剩余红包大于最大金额
if (remain.compareTo(MAX_MONEY)>0){
System.out.println("最大金额"+MAX_MONEY);
//随机生成1到最大金额的值
final int nextInt = random.nextInt(MAX_MONEY.subtract(MIN_MONEY).intValue());
//则最后一个红包=最大金额-最小金额,因为得到的红包最后会在加上最小金额
redPeck=new BigDecimal(nextInt);
}else {
//否则最后一个红包=剩余红包
redPeck = remain;
}
}else{
//加此判断是当最开始的时候剩余金额为0,则说明总金额=最小金额*个数,
//此时不需要生成随机红包,每个人领的都一样
if(remain.compareTo(new BigDecimal("0")) > 0){
redPeck=createRedPack(remain,max,MIN_MONEY,num,i);
}
}
//如果剩余红包大于当前生成的红包金额
if(remain.compareTo(redPeck) > 0){
//剩余红包=剩余红包-当前生成的红包金额
remain = remain.subtract(redPeck);
}else{
//否则剩余红包=0
remain = BigDecimal.ZERO;
}
redPeck = MIN_MONEY.add(redPeck);
moneys.add(redPeck);
}
return moneys;
}
private static BigDecimal createRedPack(BigDecimal remain,BigDecimal max, BigDecimal min ,BigDecimal num, int i){
//随机生成1到100的值
final int nextInt = random.nextInt(100);
//二倍均值计算公式:2 * 剩余金额/剩余红包数
BigDecimal redPeck = new BigDecimal(nextInt).
multiply(remain.multiply(two).divide(num.subtract(new BigDecimal(i)),2, RoundingMode.CEILING))
.divide(hundred,2, RoundingMode.FLOOR);
//如果大于最大红包,重新递归生成
if (redPeck.compareTo(max)>0){
return createRedPack(remain,max,min,num,i);
}
//如果小于最小红包,重新递归生成
if (redPeck.compareTo(min)<0){
return createRedPack(remain,max,min,num,i);
}
return redPeck;
}
/**
* 生成平均红包
* @param totalMoney
* @param num
* @return
*/
public static List<BigDecimal> splitAvgRedPacket(BigDecimal totalMoney, Integer num) {
//换算为分 方便计算
int intTotalMoney = totalMoney.multiply(hundred).intValue();
List<BigDecimal> moneys = new LinkedList<>();
int money = intTotalMoney/ num;
int mod = intTotalMoney % num;
BigDecimal divide = new BigDecimal(money).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
for (Integer i = 0; i < num - 1; i++) {
moneys.add(divide);
}
//最后一个总是平均数+余数
BigDecimal last = divide
.add(new BigDecimal(mod).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
moneys.add(last);
return moneys;
}
}
红包生成二倍均值法、平均分配法