zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    一个很好的在线测试编辑器(可以在线运行很多程序)
    基于angular的route实现单页面cnodejs
    微博
    jsonp跨域再谈
    打开IIS的快捷键
    PHPCMS笔记第二弹
    phpcms ——模板标签详细使用说明
    PHP流程管理,堪比小小程序
    PHP的简单易懂文件管理,可实现基本功能
    使用php ajax写省、市、区、三级联动
  • 原文地址:https://www.cnblogs.com/guangxiang/p/12218714.html
Copyright © 2011-2022 走看看