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

    背景: host平台 :Ubuntu 16.04 arm平台 : S5P6818 jpeg :v9c arm-gcc :4.8.1 主机准备: 运行以下脚本: ## # Copyright By Sc ...

  2. Visual Studio中的“build”、“rebuild”、“clean”的区别

    区别 rebuild基本相当于clean+build build只针对修改过的文件进行编译,rebuild会对所有文件编译(无论是否修改). clean 删除中间和输出文件,中间文件是指一些生成应用的 ...

  3. Metasploit学习笔记——客户端渗透攻击

    1.浏览器渗透攻击实例——MS11-050安全漏洞 示例代码如下 msf > use windows/browser/ms11_050_mshtml_cobjectelement msf exp ...

  4. Java集合基于JDK1.8的LinkedList源码分析

    上篇我们分析了ArrayList的底层实现,知道了ArrayList底层是基于数组实现的,因此具有查找修改快而插入删除慢的特点.本篇介绍的LinkedList是List接口的另一种实现,它的底层是基于 ...

  5. flower——知识总结

    创建主外键关联的话,外键表的外键字段一定要与主键表的主键字段相一致,包括字段类型,字段长度,字段符号等等 inverse="true" 将控制权交给对方,在一对多的关系中,一端控制 ...

  6. 吴裕雄--天生自然java开发常用类库学习笔记:同步与死锁

    class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public void run(){ for(int ...

  7. 一些linux基础命令

    linux基本命令: mkdir -p a/b/c (-p 递归创建目录) tree a (a是文件名) :可以查看某个文件的文件结构(ps:a)创建一个.txt文件 touch 文件名.txt 批量 ...

  8. idea中使用maven运行wordcount代码

    1.创建maven项目 pom文件: <?xml version="1.0" encoding="UTF-8"?> <project xmln ...

  9. 117-PHP在外部无法调用private类成员函数

    <?php class ren{ //定义人类 public function walk(){ //定义public成员方法 echo '我会走路.'; } private function d ...

  10. 吴裕雄--天生自然C++语言学习笔记:C++ STL 教程

    C++ STL(标准模板库)是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量.链表.队列.栈. C++ 标准模板库的核心包括以 ...