java红包正态分布,微信红包算法探讨
今年过年微信红包成了全民焦点,虽然大多数的红包就一块八角的样子,还是搞得大家乐此不彼地,蛋爷我年三十晚什么都没干就守在手机旁边不是摇手机红包就是抢群红包。作为一名程序猿,自然会想了解下红包的实现细节。我在网上谷歌了下,微信目前是没有公布红包的实现细节的,所以这里就提出一个自己的方案。
微信红包规则
红包领了不少,据观察红包主要有以下几个限制条件:
所有人都能分到红包,也就是不会出现红包数值为0的情况。
所有人的红包数值加起来等于支付的金额。
红包波动范围比较大,约5%~8%的红包数值在平均值的两倍以上,同时数额0.01出现的概率比较高。
红包的数值是随机的,并且数值的分布近似于正态分布。
这里假设红包的总金额为T,红包个数为k,第i个红包的金额为ai,红包金额生成函数为rand(之后会讨论这个函数)。
因为每个红包的最小值为0.01,所以在初始的时候为每个红包预留0.01元,那么剩余金额总数为T-0.01*k。
为了让每个红包金额都是随机的,红包将会由系统逐一生成,金额为当前剩余金额范围内的随机数。算法如下:
ai = rand(T - 0.01 * k - a0 - ... - ai-1)
正态分布的实现
由于C++等语言提供的随机函数是平均分布的,因此如果需要使红包金额近似正态分布,需要对平均分布进行Box–Muller转换操作,C++实现代码如下:
#define TWO_PI 6.2831853071795864769252866
#include
#include
double generateGaussianNoise(const double mu, const double sigma)
{
using namespace std;
static bool haveSpare = false;
static double rand1, rand2;
if(haveSpare)
{
haveSpare = false;
return (sigma * sqrt(rand1) * sin(rand2)) + mu;
}
haveSpare = true;
rand1 = rand() / ((double) RAND_MAX);
if(rand1 < 1e-100) rand1 = 1e-100;
rand1 = -2 * log(rand1);
rand2 = (rand() / ((double) RAND_MAX)) * TWO_PI;
return (sigma * sqrt(rand1) * cos(rand2)) + mu;
}
函数generateGaussianNoise的两个参数为期望值mu和标准差sigma,显然,mu的值为当前红包的均值,令分配第i个红包时所剩总金额为Ti,所以:
Ti = T - 0.01 * k - a0 - ... - ai-1
易得:
mu = Ti / (k - i)
sigma的值
红包数额的分布并不完全符合正太分布,因为每个红包的数额都有上限和下限,所以准确地说应该是截尾正态分布,在这里红包金额范围为[0, Ti]。
剩下要做的就是确定sigma的数值,sigma的值会直接影响红包数额的分布曲线。
根据正态分布的三个sigma定理, 生成的随机数值有95.449974%几率落在(mu-2*sigma,mu+2*sigma)内,为了使得mu-2*sigma = 0,sigma = mu/2。对于生成的随机数落在[0, Ti]以外区间的情况,采用截断处理,统一返回0或者Ti。也就是说,最后生成的随机数值分别有大约6%的几率为0或者大于2*mu,加上保留的0.01,符合条件3列出的情况。最后给出这部分C++的代码:
#include
vector generateMoneyVector(const double mon, const int pics)
{
vector valueVec;
double moneyLeft = mon - pics * 0.01;
double mu, sigma;
double noiseValue;
for(int i = 0; i < pics - 1; i++)
{
mu = moneyLeft / (pics - i);
sigma = mu / 2;
noiseValue = generateGaussianNoise(mu, sigma);
if(noiseValue < 0) noiseValue = 0;
if(noiseValue > moneyLeft) noiseValue = moneyLeft;
valueVec.push_back(noiseValue + 0.01);
moneyLeft -= noiseValue;
}
return valueVec;
}
对于收到抢红包的请求的时候,只需要进行pop操作并返回即可。
结语
这里还有一些细节没有处理,例如对返回值进行小数位数的处理等,就不做细致说明了。以上只是我对微信红包算法的一种个人猜想,有不足的地方望多指教。
References
转载请注明
java红包正态分布,微信红包算法探讨相关推荐
- java红包正态分布_红包分配算法
微信红包的分配算法,在知乎上已经有人讨论过了,详见<微信红包的随机算法是怎样实现的?>.基本的原则是:红包分配的钱数满足截尾正态随机数分布. 大致为在截尾正态分布中取随机数,并用其求和数除 ...
- java写的微信红包算法--田小江
写了一个微信红包的算法,记录一下,后续争取再优化一下,大佬们也帮忙看一下. import java.util.HashMap; import java.util.Map;public class WX ...
- Java商户发送微信红包给用户
在一定的逻辑下执行发送微信红包给用户,为了加深印象记录一下,友好的方法欢迎提出! 在微信支付-->开发者文档中,能看到 现金红包-->产品说明/操作指导的文档,如下 然后,这里需要注意的 ...
- java运气红包_教你用java做个微信红包,自己做运气王!
*/public class RedPacketUtil { //微信红包的最大值和最小值,和最大红包金额系数 private static final float MINMUM = 0.01f; p ...
- java实现微信抢红包_GitHub - collection8899/RedPackage: java 实现仿照微信抢红包算法
实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如 ...
- java 实现仿照微信抢红包算法,实测结果基本和微信吻合,附demo
实现拼手气红包算法,有以下几个需要注意的地方: 抢红包的期望收益应与先后顺序无关 保证每个用户至少能抢到一个预设的最小金额,人民币红包设置的最小金额一般是0.01元,如果需要发其他货币类型的红包,比如 ...
- python爬虫爬微信红包_python 微信红包
def redbags(money, num=10): import random choice = random.sample(range(1, money * 100), num - 1) cho ...
- css 微信红包,js微信红包实现方案
大家肯定都使用过微信的红包功能,对微信红包的规则有一定的了解,它的规则是用户可以输入金额和红包的个数,然后供其他人去抽取,每个人最少可以抽到0.01元.一般最多可以抽到200元,那这个微信红包的效果是 ...
- python微信红包_python 微信红包
def redbags(money, num=10): import random choice = random.sample(range(1, money * 100), num - 1) cho ...
- python随机发红包_python 微信红包随机金额
直接上代码吧 # -*- coding: utf-8 -*- from decimal import Decimal, InvalidOperation import random def money ...
最新文章
- python 爬虫源代码-Python爬虫学习之获取指定网页源码
- how to identify keywords for search on Google Scholar?
- 利用Android Studio快速搭建App
- django-模板文件加载顺序
- Linux学习笔记---Cortex-A7 常用汇编指令
- HTML注释的表示方法,如何表示HTML注释
- 为什么没人会 COBOL 编程了?
- 51Nod-1134 最长递增子序列【LIS】
- 分享数百个 HT 工业互联网 2D 3D 可视化应用案例之 2019
- C51 单片机入门——软件仿真
- Linux上恢复被删除的文件或目录
- Ubuntu关闭自动更新
- 2018年「编码美丽」公众号精华帖总结,建议收藏(文末赠书)!
- 关于拼板邮票孔制作规范
- 为大家推荐几个不错的公众号!
- 对8086的存储器扩展
- Android系统升级
- FLV格式文件如何转换成MP4格式 1
- i78700k配什么显卡好_i7 8700配什么显卡好 最新适合搭配i7-8700的显卡推荐
- 老掉牙的ASP文件的加密与解密