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;
}

猜你喜欢

转载自www.cnblogs.com/guangxiang/p/12218714.html
今日推荐