一个 总数和分配几个点的数据, 但是又不能是平均值,所以写一个随机分配数,每个数的和加在一起等于总金额
类似于红包分配方式,解释说明都写在类里了
解释和说明
* 1 抢红包的期望收益应与先后顺序无关
2 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如区块链货币或者积分,需要自定义一个最小金额。
3 所有抢红包的人领取的子红包的金额之和加起来,等于发红包的人发出的总红包的金额。 下面实现的方式是一次生成所有的子红包,让用户按顺序领取。也可以每领取一个生成一个,两种方式性能上各有优劣。
* public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode)
第一个参数是除数,第二个参数代表保留几位小数,第三个代表的是使用的模式。其中我们标题上就是其中的两种
BigDecimal.ROUND_DOWN:直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2
BigDecimal.ROUND_UP:直接进位,比如1.21如果保留1位小数,得到的就是1.3
BigDecimal.ROUND_HALF_UP:四舍五入,2.35保留1位,变成2.4
BigDecimal.ROUND_HALF_DOWN:四舍五入,2.35保留1位,变成2.3
总体红包算法, 1 定义总金额和红包个数 2 确定红包的最大值和最小值
3 在最大值里随机分配一个小数与之相乘,等到的是实际红包金额
4 再减去已经生成领取的红包金额和个数。接着下一次再重新计算红包;
大致如下,
max = moneytotal/count*2;
实际红包金额= max*Math.random();
2.4=4*0.6 红包大小取决于随机大小(0.1~0.9)之间
import java.math.BigDecimal;
/*
* 1 抢红包的期望收益应与先后顺序无关
2 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如区块链货币或者积分,需要自定义一个最小金额。
3 所有抢红包的人领取的子红包的金额之和加起来,等于发红包的人发出的总红包的金额。 下面实现的方式是一次生成所有的子红包,让用户按顺序领取。也可以每领取一个生成一个,两种方式性能上各有优劣。
* public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode)
第一个参数是除数,第二个参数代表保留几位小数,第三个代表的是使用的模式。其中我们标题上就是其中的两种
BigDecimal.ROUND_DOWN:直接省略多余的小数,比如1.28如果保留1位小数,得到的就是1.2
BigDecimal.ROUND_UP:直接进位,比如1.21如果保留1位小数,得到的就是1.3
BigDecimal.ROUND_HALF_UP:四舍五入,2.35保留1位,变成2.4
BigDecimal.ROUND_HALF_DOWN:四舍五入,2.35保留1位,变成2.3
————————————————
总体红包算法, 1 定义总金额和红包个数 2 确定红包的最大值和最小值
3 在最大值里随机分配一个小数与之相乘,等到的是实际红包金额
4 再减去已经生成领取的红包金额和个数。接着下一次再重新计算红包;
大致如下,
max = moneytotal/count*2;
实际红包金额= max*Math.random();
2.4=4*0.6 红包大小取决于随机大小(0.1~0.9)之间
*/
public class RedPackageTask {
public static BigDecimal getRandomMoney(RedPackage _redPackage) {
// remainSize 剩余的红包数量
// remainMoney 剩余的钱
if (_redPackage.remainSize == 1) {
_redPackage.remainSize--;
return _redPackage.remainMoney.setScale(2, BigDecimal.ROUND_DOWN);
}
BigDecimal random = BigDecimal.valueOf(Math.random());
BigDecimal min = BigDecimal.valueOf(0.01);
BigDecimal halfRemainSize = BigDecimal.valueOf(_redPackage.remainSize).divide(new BigDecimal(2), BigDecimal.ROUND_UP);
BigDecimal max1 = _redPackage.remainMoney.divide(halfRemainSize, BigDecimal.ROUND_DOWN);
BigDecimal minRemainAmount = min.multiply(BigDecimal.valueOf(_redPackage.remainSize - 1)).setScale(2, BigDecimal.ROUND_DOWN);
BigDecimal max2 = _redPackage.remainMoney.subtract(minRemainAmount);
BigDecimal max = (max1.compareTo(max2) < 0) ? max1 : max2;
BigDecimal money = random.multiply(max).setScale(2, BigDecimal.ROUND_DOWN);
money = money.compareTo(min) < 0 ? min: money;
_redPackage.remainSize--;
_redPackage.remainMoney = _redPackage.remainMoney.subtract(money).setScale(2, BigDecimal.ROUND_DOWN);;
return money;
}
public static void main(String[] args) {
// 模拟10次抢红包,每次抢到的数据
for (int i = 0; i < 10; i++) {
RedPackage moneyPackage = new RedPackage();
moneyPackage.remainMoney = BigDecimal.valueOf(1000);//总金额
moneyPackage.remainSize = 9;//红包个数
//moneyPackage.remainSize > 0 应该是个数大于0,不然会死循环
while (moneyPackage.remainSize != 0) {
System.out.print(getRandomMoney(moneyPackage) + " ");
}
System.out.println();
}
//每次抢的时候生成红包,实时生成红包,
RedPackage moneyPackage = new RedPackage();
//实时红包就要把remainMoney总金额和remainSize红包个数设置为动态,每抢一个就减掉总金额和红包个数
moneyPackage.remainMoney = BigDecimal.valueOf(1000);//总金额
moneyPackage.remainSize = 10;//红包个数
//moneyPackage.remainSize > 0 应该是个数大于0,不然会死循环
if (moneyPackage.remainSize != 0) {
System.out.print(getRandomMoney(moneyPackage) + " ");
}
System.out.println();
}
}
class RedPackage {
int remainSize;
BigDecimal remainMoney;
}