微信红包随机算法实现

       看了微信红包的算法实现探讨(基于PHP)一文,我尝试使用C++重现,代码如下:

#include <iostream>
#include <cstdlib>
#include <ctime>

int Random(int _max)
{
    _max = _max > 0 ? _max : 1;
    static bool begin = false;
    if (!begin)
    {
        srand((unsigned)time(nullptr)); //用于保证是随机数
        begin = true;
    }
    return rand() % _max;  //用rand产生随机数并设定范围
}

int main()
{
    using namespace std;
    double total_money = 10;
    int total_people = 8;
    double min_money = 0.01;

    double *per_money = new double[total_people];

    for (int i = 0; i < total_people - 1; i++)
    {
        double safe = (total_money - (total_people - i)*min_money) / (total_people - i);
        double var_money = min_money + (double)Random((int)safe * 100) / 100;
        per_money[i] = var_money;
        total_money -= var_money;
    }
    per_money[total_people - 1] = total_money;
    for (int i = 0; i < total_people; i++)
    {
        cout << i << ": " << per_money[i] << endl;
    }

    delete[] per_money;
    return 0;
}

       程序运行效果不太理想,最后一个红包金钱额数总是5~10倍于其它红包,这是由于C++提供的随机函数是均匀分布的。运行效果:共10元,8个红包,分配为0.49、0.24、0.01、0.31、0.64、1.33、1.2、5.78。

       在网上查找到这一篇微信红包算法探讨,对代码重新封装如下,运行效果不错:

random.h

#ifndef MY_RANDOM_H
#define MY_RANDOM_H

#include <cstdlib>
#include <ctime>

namespace keyven
{
    int rand()
    {
        static bool begin = false;
        if (!begin)
        {
            srand((unsigned)time(nullptr)); //用于保证是随机数
            begin = true;
        }
        return std::rand();  //用rand产生随机数并设定范围
    }
}

#endif

money.h

#ifndef MY_MONEY_H
#define MY_MONEY_H

#include "random.h"
#include <cmath>
#include <vector>

#define TWO_PI 6.2831853071795864769252866

namespace danye_me
{
    double generateGaussianNoise(const double mu, const double sigma)
    {
        static bool haveSpare = false;
        static double rand1, rand2;

        if (haveSpare)
        {
            haveSpare = false;
            return (sigma * sqrt(rand1) * sin(rand2)) + mu;
        }

        haveSpare = true;

        rand1 = keyven::rand() / ((double)RAND_MAX);
        if (rand1 < 1e-100) rand1 = 1e-100;
        rand1 = -2 * log(rand1);
        rand2 = (keyven::rand() / ((double)RAND_MAX)) * TWO_PI;

        return (sigma * sqrt(rand1) * cos(rand2)) + mu;
    }

    std::vector<double> generateMoneyVector(const double mon, const int pics)
    {
        std::vector<double> valueVec;
        double moneyLeft = mon - pics * 0.01;
        double mu, sigma;
        double noiseValue;
        double TempSum = 0;

        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((int)((noiseValue + 0.01) * 100) / (double)100);
            TempSum += (int)((noiseValue + 0.01) * 100) / (double)100;
            moneyLeft -= noiseValue;
        }

        valueVec.push_back(mon - TempSum);
        return valueVec;
    }
}

#endif

main.cpp

#include "money.h"
#include <iostream>
#include <iomanip>

int main()
{
    double total_money = 10.8;
    int people = 7;
    double Test_Sum = 0;
    std::vector<double> packets = danye_me::generateMoneyVector(total_money, people);
    for (std::vector<double>::iterator it = packets.begin(); it != packets.end(); it++)
    {
        std::cout << std::setprecision(2) << std::setiosflags(std::ios::fixed | std::ios::showpoint) << *it << std::endl;
        Test_Sum += *it;
    }
    std::cout << "Sum: " << Test_Sum << std::endl;

    system("pause");
    return 0;
}

       运行效果:共10.8元,7个红包,分配为0.87、1.53、1.90、1.92、2.25、0.79、1.54。

       有兴趣可以再看看这篇:微信红包的架构设计简介

Reference

微信红包的算法实现探讨(基于PHP)

微信红包算法探讨

微信红包的架构设计简介

转载于:https://my.oschina.net/keyven/blog/618285

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值