Java 微信红包二倍均值法,使用 BigDecimal 处理金额,确保精度,并支持自定义均值波动范围

使用 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 元
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十方来财

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值