java使用BigDecimal 實現隨機金額紅包拆分算法


原創代碼,引用注明出處:https://www.cnblogs.com/guangxiang/p/12218714.html

@Service
public class SplitRedPacketsServiceImpl implements SplitRedPacketsService {
//紅包最大金額
private static final BigDecimal MAXMONEY = new BigDecimal("200");

/**
* 紅包拆分生成list集合
* 1.生成count個紅包的list,將最小金額分配到每個紅包上
* 2.隨機生成一個數值,在原list上做加法
* @param money 總金額
* @param count 總數
* @param minmoney 最小金額
* @param maxmoney 最大金額
* @param bigred 大包固定金額
* @param bigcount 大包個數
* @return
*/
public List<BigDecimal> splitRedPackets(BigDecimal money, BigDecimal maxmoney, BigDecimal minmoney, BigDecimal count, BigDecimal bigred, BigDecimal bigcount)
{
//計算小包金額總數和總金額
count = count.subtract(bigcount);
money = money.subtract(bigcount.multiply(bigred));

//大包固定金額集合
List<BigDecimal> bigList = new ArrayList<BigDecimal>();
for(int i=0;i<bigcount.intValue();i++)
{
bigList.add(bigred);
}

//原始list--小包list
List<BigDecimal> list = new ArrayList<BigDecimal>();
maxmoney = (maxmoney.compareTo(MAXMONEY)==1)?MAXMONEY:maxmoney;

/**
* 1.將最小金額分配到每個紅包上
* 2.減去分配的小包金額
* 3.剩余總金額 =總金額-最小金額*最小金額數
*/
for(int i=0;i<count.intValue();i++)
{
list.add(minmoney);
}
BigDecimal minsum = minmoney.multiply(count);
BigDecimal totalMoney = money.subtract(minsum);
BigDecimal realMaxmoney = maxmoney.subtract(minmoney);

//判斷是否符合取值區間
if(!isRight(totalMoney,count,realMaxmoney,new BigDecimal("0")))
{
return null;
}

//合並后的新包
List<BigDecimal> listnew = new ArrayList<BigDecimal>();
for(int i=0;i<list.size();i++)
{
BigDecimal one = randomRedPacket(totalMoney,new BigDecimal("0"),realMaxmoney,new BigDecimal(count.intValue()-i));
listnew.add(list.get(i).add(one));
totalMoney = totalMoney.subtract(one);
}

//合並打包固定金額集合
listnew.addAll(bigList);
Collections.shuffle(listnew);
return listnew;
}


/**
* 隨機方法產生一個在最大值和最小值之間的一個紅包,
* 並判斷該紅包是否合法,是否在產生這個紅包之后紅包金額變成負數。
* 另外,在這次產生紅包值較小時,下一次就產生一個大一點的紅包。
* @param money 總金額
* @param mins 最小金額
* @param maxs 最大金額
* @param count 紅包總數
* @return
*/
private BigDecimal randomRedPacket(BigDecimal money,BigDecimal mins,BigDecimal maxs,BigDecimal count)
{
if(count.intValue()==1)
{
return money.setScale(2,BigDecimal.ROUND_UP);
}
if(mins.compareTo(maxs)==0 )
{
return mins;//如果最大值和最小值一樣,就返回mins
}
BigDecimal max = (maxs.compareTo(money)==1)?money:maxs;
//返回指定范圍的隨機數,保留兩位小數
BigDecimal random = BigDecimal.valueOf(Math.random());
BigDecimal middle = maxs.subtract(mins);
BigDecimal middle2 = random.multiply(middle).setScale(2, BigDecimal.ROUND_HALF_UP);
BigDecimal one = middle2.add(mins);

BigDecimal moneyOther = money.subtract(one);
if(isRight(moneyOther,count.subtract(new BigDecimal("1")),maxs,mins))
{
return one;
}
else{
//重新分配
BigDecimal avg = moneyOther.divide(count.subtract(new BigDecimal("1")),2,BigDecimal.ROUND_UP);
if(avg.compareTo(mins)==-1)
{
return randomRedPacket(money,mins,one,count);
}else if(avg.compareTo(maxs)==1)
{
return randomRedPacket(money,one,maxs,count);
}
}
return one;
}

/**
* 判斷是否符合取值區間
* @param money 總金額
* @param count 總數
* @return
*/
private boolean isRight(BigDecimal money,BigDecimal count,BigDecimal maxs,BigDecimal mins)
{
BigDecimal avg = money.divide(count,2,BigDecimal.ROUND_UP);
if(avg.compareTo(mins) ==-1){
return false;
}
else if(avg.compareTo(maxs) ==1)
{
return false;
}
return true;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM