微信红包算法探讨

标签: 微信 算法 | 发表时间:2015-02-23 00:11 | 作者:蛋爷微醺
出处:http://segmentfault.com/blogs

今年过年微信红包成了全民焦点,虽然大多数的红包就一块八角的样子,还是搞得大家乐此不彼地,蛋爷我年三十晚什么都没干就守在手机旁边不是摇手机红包就是抢群红包。作为一名程序猿,自然会想了解下红包的实现细节。我在网上谷歌了下,微信目前是没有公布红包的实现细节的,所以这里就提出一个自己的方案。

微信红包规则

红包领了不少,据观察红包主要有以下几个限制条件:
1. 所有人都能分到红包,也就是不会出现红包数值为0的情况。
2. 所有人的红包数值加起来等于支付的金额。
3. 红包波动范围比较大,约5%~8%的红包数值在平均值的两倍以上,同时数额0.01出现的概率比较高。
4. 红包的数值是随机的,并且数值的分布近似于正态分布。

这里假设红包的总金额为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 <cmath>
#include <cstdlib>
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>
vector<double> generateMoneyVector(const double mon, const int pics)
{
    vector<double> 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

  1. http://en.wikipedia.org/wiki/Normal_distribution
  2. http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform

转载请注明

原文地址: http://mafagan.sinaapp.com/2015/02/21/wechat-lishi/

相关 [微信 红包 算法] 推荐:

微信红包算法探讨

- - SegmentFault 最新的文章
今年过年微信红包成了全民焦点,虽然大多数的红包就一块八角的样子,还是搞得大家乐此不彼地,蛋爷我年三十晚什么都没干就守在手机旁边不是摇手机红包就是抢群红包. 作为一名程序猿,自然会想了解下红包的实现细节. 我在网上谷歌了下,微信目前是没有公布红包的实现细节的,所以这里就提出一个自己的方案. 红包领了不少,据观察红包主要有以下几个限制条件:.

微信红包金额分配的算法

- - 后端技术 by Tim Yang
虽然春节已经过去一段时间,但不少微信群里面依旧乐此不疲的在玩发红包活动,用户自发的将最初的一个春节拜年的场景功能慢慢演化成一个长尾功能. 用户在微信中抢红包时分成抢包和拆包两个操作. 抢包决定红包是否还有剩余金额,但如果行动不够迅速,在拆包阶段可能红包已经被其他用户抢走的情况. 据某架构群腾讯财付通专家反馈,红包的金额是拆的时候实时计算,而不是预先分配,实时计算基于内存,不需要额外存储空间,并且实时计算效率也很高.

一个红包随机分配算法

- - 樂天笔记
本文简单的讨论一下随机分配红包的算法实现. Python的random库提供了randint函数用于得到整数a和整数b之间的一个随机的整数(包括a和b,其中a<=b). randint函数可以基于random函数实现. random函数可以随机生成 [0.0, 1.0)之间的一个小数,注意是左闭右开的区间.

微信红包实现原理

- - PHP源码阅读,PHP设计模式-胖胖的空间
以下内容来源于QCon某高可用架构群聊天记录整理 背景:有某个朋友咨询微信红包的架构,在官方或非官方同学的解释和讨论中得出以下讨论内容,在此期间有多个同学发红包做现网算法测试. 当有人在群里发了一个N人的红包,总金额M元,后台大概发生的事情如下:. 在数据库中增加一条红包记录,存储到CKV,设置过期时间;.

从微信红包看微信社交关系链

- - 人人都是产品经理
马年的春节,微信红包是最成功的移动互联网产品,短短几天内就有几千万人参与,很漂亮的病毒营销产品,为微信绑定银行卡支付立下了汗马功劳. 至于微信红包的成功之处,不外乎各路媒体提到的几点:一、微信庞大而活跃的用户群体;二、巧妙的踩准了过年发红包的习俗;三、微信社交关系链的威力. 不过这样的解读稍微有点粗疏,不妨再深入的想一想,微信红包是怎样引爆流行的,有何特别之处.

微信红包真有那么火?PR忙否认

- - 钛媒体网
钛媒体注:春节期间的 微信红包火了后,微信团队,主要是红包团队并没有忙着宣传红包有多火,而是急于证明,红包其实没有传说中的那么火. 对于各种流传的比如支付用户过亿的数据等都连忙否认,微信PR澄清的相关数据是,截止除夕夜,平均每个红包10.7元,抢了最多红包的:869个. 除夕夜参与红包活动的总人数达到482万,最高峰出现在零点时分,瞬间峰值达到每分钟2.5万个红包被拆开.

微信红包的架构设计简介

- - 鸟窝
来源于QCon某高可用架构群整理,整理 by 朱玉华. 背景:有某个朋友在朋友圈咨询微信红包的架构,于是乎有了下面的文字(有误请提出,谢谢). 概况:2014年微信红包使用 数据库硬抗整个流量,2015年使用 cache抗流量. 答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储.

微信晒单红包大数据:80后最多 广东最壕

- - cnBeta.COM
逢年过节微信抢红包已成为国人最喜爱的生活方式之一,科客从微信官方获悉,春节前微信团队一方面在加紧新春期间服务稳定性的测试与准备,另一方面抽空公布了2016年微信红包使用习惯的多项数据,下面带各位了解相关详情. 1、80后最爱收发微信红包,90后紧随其后. 数据显示2016年全年,80后是收发微信红包最活跃的群体,无论是“收红包”还是“发红包”,次数上都领先于其他年龄层.

你是如何被微信广告选中的?微信广告引擎与社交传播算法实践

- - 36氪
编者按:本文来自微信公众号 “InfoQ”(ID:infoqchina),作者陈功;36氪经授权发布. 微信广告自 2014 年上线以来,分别发布了公众号与朋友圈广告. 微信广告系统承载了每天十亿级以上的访问量,紧密与微信平台生态相结合,同时利用了腾讯大数据体系进行效果优化. 本文首先会给大家展示微信广告的整体系统架构,并介绍重要的功能模块和数据流程.

缓存算法

- lostsnow - 小彰
没有人能说清哪种缓存算法由于其他的缓存算法. (以下的几种缓存算法,有的我也理解不好,如果感兴趣,你可以Google一下  ). 大家好,我是 LFU,我会计算为每个缓存对象计算他们被使用的频率. 我是LRU缓存算法,我把最近最少使用的缓存对象给踢走. 我总是需要去了解在什么时候,用了哪个缓存对象.