最近要做一個 總數和分配幾個點的數據, 但是又不能是平均值,所以寫一個隨機分配數,每個數的和加在一起等於總金額
類似於紅包分配方式,解釋說明都寫在類裏了
解釋和說明
* 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;
}
參考標準