微信紅包隨機算法實現

       看了微信紅包的算法實現探討(基於PHP)一文,我嘗試使用C++重現,代碼以下:ios

#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.4九、0.2四、0.0一、0.3一、0.6四、1.3三、1.二、5.78。算法

       在網上查找到這一篇微信紅包算法探討,對代碼從新封裝以下,運行效果不錯:segmentfault

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.cppdom

#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.8七、1.5三、1.90、1.9二、2.2五、0.7九、1.54。函數

       有興趣能夠再看看這篇:微信紅包的架構設計簡介spa

Reference

微信紅包的算法實現探討(基於PHP)架構設計

微信紅包算法探討設計

微信紅包的架構設計簡介

相關文章
相關標籤/搜索