二倍均值法模拟微信抢红包金额算法规则

```java
/**
     * 二倍均值法
     * @param amount 总金额
     * @param min 最小金额
     * @param num 个数
     * 本帖只提供思路,实际应用时应根据具体情况改动
     * 内容若有错误请在评论区指正
     */
    private static void HBTest(BigDecimal amount, BigDecimal min, BigDecimal num) {
        //总金额-最小金额*个数(这东西的存在就是为了去计算每个人抢多少,还有就是保证每个包里面都有一点钱而且还不能是负数的那种),就把它叫做基数吧
        BigDecimal remain = amount.subtract(min.multiply(num));
        //永不可继承的随机数
        final Random random = new Random();
        final BigDecimal hundred = new BigDecimal("100");
        final BigDecimal two = new BigDecimal("2");
        //BigDecimal.ZERO等价于new BigDecimal(0),BigDecimal.ZERO为BigDecimal的常量数组,直接取出来用就行了,避免重复创建对象
        BigDecimal sum = BigDecimal.ZERO;
        //这个就是说这个人抢了多少钱,通过遍历里面的if else赋值
        BigDecimal redpeck;
        //普通遍历,num.intValue()意为输出一个int数据,实际应用的时候可不能这么遍历(你品你细品)
        for (int i = 0; i < num.intValue(); i++) {
            //生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n,这里的n为100
            final int nextInt = random.nextInt(100);
            //最后一个人抢的金额,这里好像有问题,应该是remain = amount.subtract(sum)也就是最后一个人把剩下的所有钱都领走,但是上下文呼应的话好像还只能这么写
            if(i == num.intValue() -1) redpeck = remain;
            /*知识点来了小本本拿出来记好(不保证全对,需要验证),内容参考博主well386文章BigDecimal的四舍五入的RoundingMode选择
              RoundingMode.UP,远离零方向舍入的舍入模式。始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值
              RoundingMode.DOWN,向零方向舍入的舍入模式。从不对舍弃部分前面的数字加 1(即截尾)。注意,此舍入模式始终不会增加计算值的绝对值
              RoundingMode.CEILING,向正无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于  RoundingMode.UP;如果结果为负,则舍入行为类似于  RoundingMode.DOWN。
                                   注意,此舍入模式始终不会减少计算值
              RoundingMode.FLOOR,向负无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于  RoundingMode.DOWN;如果结果为负,则舍入行为类似于 RoundingMode.UP。
                                  注意,此舍入模式始终不会增加计算值
              RoundingMode.HALF_UP,向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。如果被舍弃部分 >= 0.5,则舍入行为同  RoundingMode.UP;
                                    否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入
              RoundingMode.HALF_DOWN,向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。如果被舍弃部分 > 0.5,则舍入行为同  RoundingMode.UP;
                                      否则舍入行为同 RoundingMode.DOWN
              RoundingMode.HALF_EVEN,向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;
                                     如果为偶数,则舍入行为同 RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。
                                     此舍入模式类似于 Java 中对 float 和 double 算法使用的舍入策略
              RoundingMode.UNNECESSARY,用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。如果对生成精确结果的操作指定此舍入模式,则抛出  ArithmeticException
             */
            //不是最后一个人,金额=随机数*(基数*two)/(个数-第几次循环)/hundred
            else redpeck = new BigDecimal(nextInt).multiply(remain.multiply(two).divide(num.subtract(new BigDecimal(i)),2,RoundingMode.CEILING)).divide(hundred,2, RoundingMode.FLOOR);
            //基数大于抢到的金额,基数重新赋值,基数=基数-抢到的金额向上取整保留两位小数
            if(remain.compareTo(redpeck) > 0) remain = remain.subtract(redpeck).setScale(2, BigDecimal.ROUND_HALF_UP);
            //如果基数比抢到的金额小,那就给它重新赋值为0
            else remain = BigDecimal.ZERO;
            //统计一下已经被领了多少
            sum = sum.add(min.add(redpeck)).setScale(2, BigDecimal.ROUND_HALF_UP);
            /*知识点来了小本本拿出来记好(不保证全对,需要验证),内容参考博主Wilson Tsai文章BigDecimal.setScale用法总结
              BigDecimal b = new BigDecimal("2.225667").setScale(2, BigDecimal.ROUND_DOWN);//输出2.22,也就是说把2.225667保留两位小数
              BigDecimal c = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_UP);//输出2.23,保留两位小数并且向上取整
              BigDecimal f = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_CEILING);输出2.23,正数,相当于BigDecimal.ROUND_UP
              BigDecimal g = new BigDecimal("-2.225667").setScale(2, BigDecimal.ROUND_CEILING);//输出-2.22,负数,相当于BigDecimal.ROUND_DOWN
              BigDecimal h = new BigDecimal("2.225667").setScale(2, BigDecimal.ROUND_FLOOR);//输出2.22,正数,相当于BigDecimal.ROUND_DOWN
		      BigDecimal i = new BigDecimal("-2.224667").setScale(2, BigDecimal.ROUND_FLOOR);//输出-2.23,负数,相当于BigDecimal.ROUND_HALF_UP
              BigDecimal d = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_UP);//输出2.23,四舍五入(若舍弃部分>=5,就进位)
              BigDecimal e = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_DOWN);//输出2.22,四舍五入(若舍弃部分>5,就进位)
              BigDecimal j = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_EVEN);//输出2.22,如果舍弃部分左边的数字为偶数,则作   ROUND_HALF_DOWN
		      BigDecimal k = new BigDecimal("2.215").setScale(2, BigDecimal.ROUND_HALF_EVEN);//输出2.22,如果舍弃部分左边的数字为奇数,则作   ROUND_HALF_UP
		      BigDecimal l = new BigDecimal("2.215").setScale(3, BigDecimal.ROUND_UNNECESSARY);//断言请求的操作具有精确的结果,因此不需要舍入。
		                                                                                       //如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。
            */
            System.out.println("第"+(i+1)+"个人抢到红包金额为:"+min.add(redpeck));
        }
        System.out.println("红包总额:" + sum);//
    }

    // 测试代码
    public static void main(String[] args) {
        BigDecimal amount = new BigDecimal(100).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal min = new BigDecimal(0.01).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal num = new BigDecimal(10).setScale(2, BigDecimal.ROUND_HALF_UP);
        HBTest(amount,min,num);
    }
具体结果请自己运行main方法