微信红包随机算法实现

狂风中的少年 提交于 2019-12-03 12:24:54

       看了微信红包的算法实现探讨(基于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)

微信红包算法探讨

微信红包的架构设计简介

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!