使用 Java 的 BigDecimal 可以更精准地处理微信红包分配,特别是在需要控制均值波动范围的场景中。以下是实现微信红包分配算法的完整代码,使用 BigDecimal 处理金额,确保精度,并支持自定义均值波动范围。
需求概述
使用 BigDecimal 保证金额精度。
控制均值波动范围,例如,金额在均值的 ±20% 内随机分布。
总金额固定,不能超出或少分。
单次分配金额限制在 [minAmount, maxAmount] 范围内。
实现代码
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class BigDecimalRedEnvelope {
/**
* 分配微信红包
*
* @param totalMoney 总金额(单位:元)
* @param totalPeople 总人数
* @param minAmount 每人最小金额
* @param maxAmount 每人最大金额
* @param fluctuationRate 均值波动范围(如 0.2 表示 ±20%)
* @return 每个人分得的金额列表
*/
public static List<BigDecimal> divideRedEnvelope(BigDecimal totalMoney, int totalPeople, BigDecimal minAmount, BigDecimal maxAmount, BigDecimal fluctuationRate) {
if (minAmount.multiply(BigDecimal.valueOf(totalPeople)).compareTo(totalMoney) > 0) {
throw new IllegalArgumentException("最小金额乘以人数超过了总金额,无法分配");
}
if (maxAmount.multiply(BigDecimal.valueOf(totalPeople)).compareTo(totalMoney) < 0) {
throw new IllegalArgumentException("最大金额乘以人数小于总金额,无法分配");
}
List<BigDecimal> result = new ArrayList<>();
Random random = new Random();
for (int i = 0; i < totalPeople; i++) {
int remainingPeople = totalPeople - i;
// 动态调整分配范围
BigDecimal mean = totalMoney.divide(BigDecimal.valueOf(remainingPeople), 2, RoundingMode.HALF_UP);
BigDecimal lowerBound = mean.multiply(BigDecimal.ONE.subtract(fluctuationRate)).max(minAmount); // 最小值
BigDecimal upperBound = mean.multiply(BigDecimal.ONE.add(fluctuationRate)).min(maxAmount); // 最大值
// 生成随机金额
BigDecimal randomFactor = BigDecimal.valueOf(random.nextDouble());
BigDecimal amount = lowerBound.add(randomFactor.multiply(upperBound.subtract(lowerBound)))
.setScale(2, RoundingMode.HALF_UP);
result.add(amount);
totalMoney = totalMoney.subtract(amount); // 更新剩余金额
}
return result;
}
public static void main(String[] args) {
BigDecimal totalMoney = new BigDecimal("100.00"); // 总金额
int totalPeople = 10; // 总人数
BigDecimal minAmount = new BigDecimal("5.00"); // 每人最小金额
BigDecimal maxAmount = new BigDecimal("20.00"); // 每人最大金额
BigDecimal fluctuationRate = new BigDecimal("0.2"); // 均值波动范围 ±20%
List<BigDecimal> amounts = divideRedEnvelope(totalMoney, totalPeople, minAmount, maxAmount, fluctuationRate);
System.out.println("红包分配结果:");
for (int i = 0; i < amounts.size(); i++) {
System.out.printf("第 %d 个红包:%.2f 元\n", i + 1, amounts.get(i));
}
// 校验总金额是否正确
BigDecimal sum = amounts.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.printf("分配的总金额:%.2f 元\n", sum);
}
}
代码说明
参数解析:
totalMoney:红包总金额。
totalPeople:分配人数。
minAmount:每人最小金额。
maxAmount:每人最大金额。
fluctuationRate:均值波动范围,0.2 表示 ±20%。
动态调整范围:
使用均值 mean 计算波动范围:
BigDecimal lowerBound = mean.multiply(BigDecimal.ONE.subtract(fluctuationRate)).max(minAmount);
BigDecimal upperBound = mean.multiply(BigDecimal.ONE.add(fluctuationRate)).min(maxAmount);
随机金额生成:
通过随机因子生成 [lowerBound, upperBound] 范围内的金额:
BigDecimal randomFactor = BigDecimal.valueOf(random.nextDouble());
BigDecimal amount = lowerBound.add(randomFactor.multiply(upperBound.subtract(lowerBound)));
金额精度控制:
使用 setScale(2, RoundingMode.HALF_UP) 保证金额保留两位小数。
剩余金额校验:
每次分配后更新剩余金额,确保不超出限制。
示例输出
输入参数:
totalMoney = 100.00;
totalPeople = 10;
minAmount = 5.00;
maxAmount = 20.00;
fluctuationRate = 0.2;
输出:
复制代码
红包分配结果:
第 1 个红包:11.56 元
第 2 个红包:7.89 元
第 3 个红包:8.45 元
第 4 个红包:6.84 元
第 5 个红包:10.24 元
第 6 个红包:13.34 元
第 7 个红包:7.65 元
第 8 个红包:8.22 元
第 9 个红包:14.53 元
第 10 个红包:11.28 元
分配的总金额:100.00 元
732

被折叠的 条评论
为什么被折叠?



