原创代码,引用注明出处: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. arm linux 移植 x265

    背景 本来想着把 x265编译到ffmpeg里面,搞定了x265的编译:但是一直报ERROR: x265 not found using pkg-config这个错误,我按照网上的资料,查看了ffbu ...

  2. java csv文件写入

    List<String> list_code = null; 方案1 控制字符集: BufferedWriter bw=new BufferedWriter(new OutputStrea ...

  3. leetcode1143 Longest Common Subsequence

    """ Given two strings text1 and text2, return the length of their longest common subs ...

  4. Good Bye 2019

    A.Card Game 题目大意:两个人都有共有n张卡牌,每张卡牌上都有一个数xi,没有两张牌上的数相同,且xi不小于1不大于n.每次两个人选出一张牌来,牌上数字大的人赢得此局,如果谁最后手上拥有所有 ...

  5. Easy_vb

    拿到之后运行一下 之后使用ida打开先关键字搜索一下,结果就出来了

  6. 存储器HK1225-7EQ 使用说明书资料

    一. 引脚排列 二. 读取模式 HK1225在WE(写使能)被禁止(high)且CE(片选)被选中(Low)且CE2(片选2)被选中(High)并且OE(读信号)被使能(Low)执行一次读循环.13个 ...

  7. arduino中的serial .available()和serial.read()

    Serial.available() 的意思是:返回串口缓冲区中当前剩余的字符个数.一般用这个函数来判断串口的缓冲区有无数据,当Serial.available()>0时,说明串口接收到了数据, ...

  8. 开源DDD设计模式框架YMNNetCoreFrameWork第二篇-增加swagger,数据库迁移,增加权限模型

    1.框架去掉application层,把HOst作为application层 2.增加swagger插件 3.增加Asp.net  Identity身份验证 源代码地址:https://github. ...

  9. vuejs+thinkphp5+phpsocketIO+timer数据及时更新

    1.安装thinkphp5.0以上版本包含workerman框架2.composer安装composer require workerman/phpsocket.io3.vue中调用需要加载weapp ...

  10. jQuery原理系列-Dom Ready

    ready事件是jquery的一个很重要的功能,在很久很久以前,我们是使用window.onload监听页面加载成功的,onload事件的好处是你不用考虑浏览器兼容性,也不需要依赖任何框架就可以写,但 ...