原创代码,引用注明出处: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;
}

java使用BigDecimal 实现随机金额红包拆分算法的更多相关文章

  1. java实现微信红包分配算法

    红包算法分析 有人认为,抢红包的额度是从0.01到剩余平均值*N(N是一个系数,决定最大的红包值)之间,比如一共发了10块钱,发了10个红包:第一个人可以拿到(0.01~1*N)之间的一个红包值,当然 ...

  2. .Net Excel 导出图表Demo(柱状图,多标签页) .net工具类 分享一个简单的随机分红包的实现方式

    .Net Excel 导出图表Demo(柱状图,多标签页) 1 使用插件名称Epplus,多个Sheet页数据应用,Demo为柱状图(Epplus支持多种图表) 2 Epplus 的安装和引用 新建一 ...

  3. java.math.BigDecimal保留两位小数,保留小数,精确位数

    http://blog.csdn.net/yuhua3272004/article/details/3075436 使用java.math.BigDecimal工具类实现   java保留两位小数问题 ...

  4. Java之BigDecimal详解

    一.BigDecimal概述 ​ Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数,但在实 ...

  5. Java基础扫盲系列(二)—— Java中BigDecimal和浮点类型

    一直以来我几乎未使用过BigDecimal类型,只有在DB中涉及到金额字段时听说要用Decimal类型,但是今天再项目代码中看到使用BigDecimal表示贷款金额. 本篇文章不是介绍BigDecim ...

  6. Java的BigDecimal,对运算封装

    添加maven依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava ...

  7. flex布局中flex属性运用在随机发红包的算法上

    flex布局是现在前端基本上都会运用的一种布局,基本上用到比较多的是父元素设置display:flex,两个子元素,一个设置固定宽度,另一个设置为flex:1(这里都指flex-direction为r ...

  8. java中BigDecimal加减乘除基本用法

    Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数. 在实际应用中,需要对更大或者更小的数进 ...

  9. Java中BigDecimal的8种舍入模式

    java.math.BigDecimal 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成. 如果为零或正数,则标度是小数点后的位 ...

随机推荐

  1. Python测试进阶——(3)编写Python程序监控计算机的服务是否正常运行

    用python写了个简单的监控进程的脚本,当发现进程消失的时候,立即调用服务,开启服务. 脚本的工作原理是这样的:脚本读取配置文件,读取预先配置好的调用系统服务的路径和所要监控的服务在进程管理器中的进 ...

  2. android中的简单animation(三)accelerate(加速),decelerate(减速),anticipate,overshoot,bounce

    animation_3.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout x ...

  3. Python 使用 requests 模块发送请求的使用及封装

    一.requests 模块基本使用 1.准备接口的URL.请求参数.请求头 # 1. 构造注册.登录.充值请求的url register_url = "注册url" login_u ...

  4. 认识json,详解JsonConfig

    说到json 初学者很迷茫,不知json怎么为何物,以及怎么用.我简单说下我的了解 既然用了json 我们就要知其然也知其所以然.下面有几个疑问 1.为什么要用json?也就是json 的优势 2.我 ...

  5. JavaScript 的一些SAO操作

    IE判断检测 jQuery 在 1.9 版本之前,提供了一个浏览器对象检测的属性 .browser 的替代方案.于是各种利用 IE bug 的检测方法被搜了出来: // IE 678 最短方法 var ...

  6. vue数据变化后页面刷新

    在测试methods和conputed区别的时候,我在methods方法体内增加了一个vue数据自增语句,类似于this.abc++;导致整个页面无法加载出来. 原因是this.abc改变 会触发页面 ...

  7. 51nod 1515:明辨是非 并查集合并

    1515 明辨是非 题目来源: 原创 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 难度:6级算法题  收藏  关注 给n组操作,每组操作形式为x y p. 当p为1时,如果第x ...

  8. Pycharm使用python3无法通过HTMLTestRunner生成测试报告《转载》

    Pycharm使用python3无法通过HTMLTestRunner生成测试报告: https://blog.csdn.net/weixin_38981172/article/details/8238 ...

  9. 聚类之高斯混合模型与EM算法

    一.高斯混合模型概述 1.公式 高斯混合模型是指具有如下形式的概率分布模型: 其中,αk≥0,且∑αk=1,是每一个高斯分布的权重.Ø(y|θk)是第k个高斯分布的概率密度,被称为第k个分模型,参数为 ...

  10. 通过html5 touch事件封装手势识别组件

    html5移动端新增了touchstart,touchmove,touchend事件,利用这3个事件,判断手指的点击和划动轨迹,我们可以封装各种手势的识别功能, 这3个事件和pc端的mousedown ...