PHP实现简单发红包(随机分配,平均分配)
最近碰到一些情况,把思路重新整理了一下,敲出代码。记下来,以后可以借鉴,进一步优化等。
大致的思路:红包主要分两种,一种是平均分配,一种是随机分配。
1、平均分配
平均分配相对好理解,只要把钱平均分给每一个人就可以了
这里有一个情况,就是钱的总额是固定的,但是分配的人数,不一定可以整除余0,那么剩下的如何分配呢?
这里,剩余的钱(极少),多分到的人,也就是多分1分钱(在计算处理时,单位是“分”)
所以,使用的处理办法是,从前到后(谁手快,谁多分,蚊子再小也是肉),逐一分这剩余的钱,每人1分钱,直到钱没为止
2、随机分配
我这个随机分配,比较简单,只比平均分配多了一个步骤(此步骤根据需要,可以循环多次使用)。
先是随机分配的两个特殊情况:
a.总金额不够所有人分。例如,最小的钱是1分钱,分给10个人。是不可以的
b.总金额正好只能每人平均分1分钱。例如,0.1元,分给10个人,任何一个人多1分钱,就会有人没钱分
这两个特例单独处理
接下来的情况就是,正常的随机分钱,为了尽量让每个人分钱的概率差不多,用了下边的方法
a.先将钱按当前分钱的人数计算平均值
b.随机的钱数的取值范围是(1,平均值)
c.可以分配的总钱数减去生成的随机钱数,得到下一次分配时的可分配总钱数
d.重复a~c步骤,最终完成随机分配
按照以上的方法随机分完之后,消耗的总金额是一定小于等于输入的总金额的,那么,在处理完随机分配之后,还要对剩余的金额处理
这里实现的,就是将剩余的金额,再用平均分配的方式,分散到每一个人的手里
以上就是实现发红吧的大致思路,下边代码,就是根据这个思路整理而成
一、rand_money方法,完成一次随机分配
/*
* 随机分钱
* 参数:$money,参与分钱的金额
* $num,参与分钱的人数
*/
function rand_money($money, $num)
{
$arr = [];//结果数组
$money = $money * 100;// 将元转成分(小数计算有误差,随机数也都是整数)
$rest_money = $money;// 初始化,剩余钱的变量
$average = $rest_money / $num;// 求出均分情况下,每人的红包值 if ($average < 1) {// 钱不够所有人分
return false;
}elseif($average == 1){// 所有人平均分这笔钱(钱数只够这么分的)
for ($i=0; $i<$num; $i++) {
$arr[] = $average;
}
}else{// 每个人随机分配
for ($i=0; $i<$num; $i++) {
$range_money = round(($rest_money / ($num - $i)));
$rand_money = mt_rand(1, $range_money);
$arr[] = $rand_money;
$rest_money = $rest_money - $rand_money;// 获取剩下的钱
}
}
return $arr;
}
二、average_money方法,既可以自己完成平均分配,又可以协助随机分配,完成剩余金额的分配
function average_money($money, $num, $arr=[], $conversion_val=1)
{
$money = $money * 100;
$arr_sum = 0;//保存数组和
if (count($arr) > 0) {// 随机分配,会调用此方法将剩余的钱分掉,此数组为随机分配后的结果
foreach ($arr as $k=>$v) {
$arr[$k] = $v * 100 / $conversion_val;// 如果单位有变化这调整一下,一直以分为单位处理数据
}
$arr_sum = array_sum($arr);// 统计随机分配已经分配了总钱数
} else {
for ($i=0; $i<$num; $i++) {
$arr[] = 0;// 初始化每个人的数组,兼容下边循环处理部分
}
}
$add_money = $money - $arr_sum;
// 如果总钱数和之前随机分配的数组的总和差值为0,就说明随机分配已经将钱全部分出去了,就不需要再平均分配处理了
if ($add_money == 0) {
return $arr;
}
// 先把剩余的能均分的部分均分一下,然后若再有剩余,则从前到后,注意分配
for ($i = 0; $i < $num; $i++) {
$arr[$i] = $arr[$i] + floor($add_money / $num);// 如果之前有随机分配,则是将剩余的钱平均追加入随机分配的值里
}
$arr_sum = array_sum($arr);// 分配后,求和,用于修正最后剩余的零钱
// 如果还有剩余,这部分说明每人一分都不够,就从头开始没人一分的分下去,直到分完为止
$odd_money = bcsub($money, $arr_sum, 0);// 针对钱的计算,建议使用bc函数,普通的计算方法有误差
$i = 0;
while ($odd_money >= 1) {
$arr[$i] = $arr[$i] + 1;// 每人加1分钱
$odd_money = $odd_money - 1;// 剩余的金额,每分掉一个人,就减1分钱
$i++;
}
return $arr;
}
三、红包调用方法,根据不同类型,返回不同红包的结果
/*
* 红包方法
* 参数:$money,参与分钱的金额
* $num,参与分钱的人数
* $type,红包类型,0平均分配,1随机分配
*/
function get_red ($money, $num, $type=0) {
if ($type) { // 非0,随机红包
$arr_rand = rand_money($money, $num);// 先随机分配
$arr = average_money($money, $num, $arr_rand, 100);// 再平均分配
} else { // 平均分配红包
$arr = average_money($money, $num);
}
return $arr;
}
四、实例代码测试
$a = get_red(66.61, 11, 0);
//将最终结果,转换成元为单位
foreach ($a as $k=>$val) {
$a[$k] = $val / 100;
}
print_r($a);
echo '<br />'.array_sum($a); $r = get_red(66.61, 11, 1);
//将最终结果,转换成元为单位
foreach ($r as $k=>$val) {
$r[$k] = $val / 100;
}
echo '<br />';
print_r($r);
echo '<br />'.array_sum($r);
以上的代码,就完成了红包的操作。
这代码只是,简单的实现。这其中还有特殊情况,比如,每次随机的数都是最小的数,虽然概率很低。
那么这种情况,只做一次随机分配,貌似效果并不好。毕竟后边就是平均分配了,这样每一个人的终值非常接近平均值。
所以,可以考虑,在一次随机分配之后,计算已分配总钱数,根据该总钱数判断是否需要再次进行随机分配,然后将两次或者多次随机分配的值同key合并。
最后再把剩余的金额“平均分配”后,同key加到一起。这样的结果效果更好。
注意:
1、日常人们习惯金钱的单位都是“元”,但这里,尽量转成“分”;小数计算误差大,随机数生成也都是整数
2、如果可以,金钱在计算时,尽量使用bc高精度函数。如:bcadd(加),bcsub(减),bcmul(乘),bcdiv(除)等
PHP实现简单发红包(随机分配,平均分配)的更多相关文章
- python+redis简单实现发红包程序
redis是什么? Redis 是一个高性能的key-value数据库! 想进一步了解请移步搜索引擎自行查找. 编写这个小程序的目的就是对redis进行一个简单的小操作,对redis有一个初步的了解, ...
- php简单随机实现发红包程序
前言: 使用PHP发红包,当我们输入红包数量和总金额后,PHP会根据这两个值进行随机分配每个金额,保证每个人都能领取到一个红包,每个红包金额不等,就是要求红包金额要有差异,所有红包金额总额应该等于总金 ...
- 用Python编写简单的发红包程序和计算器原理
用Python编写简单的发红包程序: 第一种解法:数轴方法解决 import random def red_packet(money,num): money = money * 100 #将钱数转换成 ...
- 使用PHP编写发红包程序
使用PHP编写发红包程序 http://www.jb51.net/article/69815.htm 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2015-07-22 微信发红 ...
- PHP+Ajax手机移动端发红包实例
基本流程:当输入完红包数量和总金额后,PHP会根据这两个值进行随机分配每个金额,保证每个人都能领取到一个红包,且每个红包金额不等,并且所有红包金额总额等于总金额. 实现原理:设定总金额为10元,有N个 ...
- PHP实现发红包程序
我们先来分析下规律. 设定总金额为10元,有N个人随机领取: N=1 第一个 则红包金额=X元: N=2 第二个 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数. 第 ...
- PHP实现发红包程序(helloweba网站经典小案例)
我们先来分析下规律. 设定总金额为10元,有N个人随机领取: N=1 第一个 则红包金额=X元: N=2 第二个 为保证第二个红包可以正常发出,第一个红包金额=0.01至9.99之间的某个随机数. 第 ...
- 微信小程序发红包
背景: 近期一个朋友公司要做活动,活动放在小程序上.小程序开发倒是不难,不过要使用小程序给微信用户发红包,这个就有点麻烦 确定模式: 小程序目前没有发红包接口,要实现的话,只能是模拟红包,即小程序上做 ...
- Python写随机发红包的原理流程
首先来说说要用到的知识点,第一个要说的是扩展包random,random模块一般用来生成一个随机数 今天要用到ramdom中unifrom的方法用于生成一个指定范围的随机浮点数通过下面的图简单看下: ...
随机推荐
- Webservice学习之WSDL详解
1. <definitions/> 这部分在基础篇里已经介绍,主要说明引用了哪些schema以及schema的位置等,可以看下基础篇的介绍,SayHello的Demo这部分内容如下: &l ...
- 学习Vue 入门到实战——学习笔记(二)
闲聊: 哈哈哈!过了好几天才更新博客啦,嘻嘻,马上过年了,大家最近是不是都开心的快飞起来了,小颖好几个朋友公司都已经放假了,可是我们公司要等到腊月29上完班才给放假,哎!心情不美气的很,用我之前大学舍 ...
- [原]Jenkins(十六) jenkins再出发之jenkins+robot+blue ocean+svn
jenkins version: 部署省略..(如有需要请查看本博客jenkins系列的文档) 新的jenkins需要先填写administratorpassword (如下图)找到下面红色的路径打开 ...
- 帝国CMS 您来自的链接不存在
网上的解决方法如下. 我是在通过接口,发布新闻,然后点击修改的时候,提示这个. 网上的方法,是让检查这个栏目下,有没有设置默认模板,包括:列表模板和内容模板,如果没有,就设定一下,再“更新数据库缓 ...
- ubuntu apt 软件源的更改
在ubuntu上面安装软件一般都使用 apt安装 在ubuntu下面有一个源列表,源列表里面都是一些网站信息,每条网址就是一个源,这个地址指向的数据标识着这台服务器上有哪些软件可以用 编辑源命令: s ...
- ruby 知识点随笔
print .puts 和 p 方法的区别."" 与 '' 的区别. 处理控制台编码问题 >ruby -E utf-8 脚本文件名称 # 执行脚本 >irb -E u ...
- 【C++ 模板迭代器实例/半素数】
题目:判断一个数是不是两个素数的乘积,是输出YES,不是输出NO.数据范围为2-1000000. 为了解决这个问题,我们继续使用STL——vector & set,分别用来存储素数和半素数.为 ...
- Javascript htmldecode
// HtmlDecode http://lab.msdn.microsoft.com/annotations/htmldecode.js // client side version of the ...
- php 延迟静态绑定: static关键字
abstract class DomainObject { public static function create() { return new self(); } } class User ex ...
- 查看Sql Server 数据库的内存使用情况
-- 查询SqlServer总体的内存使用情况 select type , sum(virtual_memory_reserved_kb) VM_Reserved , sum(virtual_memo ...