看了微信红包的算法实现探讨(基于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
来源:oschina
链接:https://my.oschina.net/u/1451225/blog/618285