// RandomTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <cmath>
#include <random>
#include <cstdint>
#include <ctime>
#include <algorithm>
#include <numeric>
#include <cassert>
#include <climits>
#include <thread>
#define XASSERT(exp) assert(exp)
#define XASSERT_MSG(exp, msg) assert(exp)
#define X_DEFAULT_FLOAT_PRECISION (0.00000001)
// @in: 总次数、目标比例(千分比)、算法类型(1.c标准库rand; 2.cpp11 mt19937)
// @out: 实际命中次数、实际命中概率
bool RandomHitTest(int32_t nTotalCount, float fHitRate, int32_t nAlgorithmType, int32_t& nRealHitCount, float& fRealHitRate);
void RandomHitTest_std_mt19937(int32_t nTotalCount, float fHitRate, int32_t& nRealHitCount, float& fRealHitRate);
void RandomHitTest_std_rand(int32_t nTotalCount, float fHitRate, int32_t& nRealHitCount, float& fRealHitRate);
// 简化std::rand获取[nMin, nMax]区间的一个数字
uint32_t StdRandEx(uint32_t nMin, uint32_t nMax);
int _tmain(int argc, _TCHAR* argv[])
{
//std::thread srandThread([](){ std::this_thread::sleep_for(std::chrono::seconds(1));});
//srandThread.detach();
std::vector<std::tuple<float, float>> vecResult;
for (int n = 0; n < 1000; n++)
{
uint32_t nTotalCount = 100000; // 基数100000次
for (float fHitRate = 0.001f; 1.f - fHitRate >= 0; fHitRate = fHitRate + 0.101f)
{
int32_t nRealHitCount = 0;
float fRealHitRate = 0;
// std::rand测试
RandomHitTest(nTotalCount, fHitRate, 1, nRealHitCount, fRealHitRate);
//std::cout << "AlgorithmType=" << 1 << ",TotlaCount=" << nTotalCount << ",HitRate=" <<
// fHitRate << ",ReahHitRate=" << std::fixed << fRealHitRate << ",RealHitCount=" << nRealHitCount << std::endl;
int32_t nRealHitCount1 = 0;
float fRealHitRate1 = 0;
// cpp11 mt19937
RandomHitTest(nTotalCount, fHitRate, 2, nRealHitCount1, fRealHitRate1);
//std::cout << "AlgorithmType=" << 2 << ",TotlaCount=" << nTotalCount << ",HitRate=" <<
// fHitRate << ",ReahHitRate=" << std::fixed << fRealHitRate1 << ",RealHitCount=" << nRealHitCount1 << std::endl;
//std::cout << "---differ rate=" << std::fixed << fRealHitRate1 - fRealHitRate << ", differ count="
// << nRealHitCount1 - nRealHitCount << std::endl;
std::tuple<float, float> tupleResult = std::make_tuple(fHitRate, std::fabsf(fRealHitRate1 - fRealHitRate));
vecResult.push_back(tupleResult);
}
}
std::sort(vecResult.begin(), vecResult.end(),
[](std::tuple<float, float>& tupLeft, std::tuple<float, float>& tupRight)->bool{
//float fHitRateL = 0;
//float fRealRateL = 0;
//float fHitRateR = 0;
//float fRealRateR = 0;
return std::get<1>(tupLeft) - std::get<1>(tupRight) > 0;;
});
auto tupleFirst = vecResult[0];
return 0;
}
uint32_t StdRandEx(uint32_t nMin, uint32_t nMax)
{
XASSERT((nMin >= 0) && (nMax >= 0) && (nMin <= nMax));
uint32_t nRandVal = 0;
if (nMin == nMax)
{
nRandVal = nMax;
}
else if (nMin < nMax)
{
nRandVal = rand() % (nMax - nMin + 1) + nMin;
}
else
{
XASSERT_MSG(0, _T("参数异常"));
}
return nRandVal;
}
void RandomHitTest_std_rand(int32_t nTotalCount, float fHitRate, int32_t& nRealHitCount, float& fRealHitRate)
{
nRealHitCount = 0;
fRealHitRate = 0;
if (nTotalCount <= 0 || fHitRate <= 0)
{
return;
}
// 计算浮点小数点个数
int32_t nWeCount = 3; // 位数(三位数,千分比精度)
XASSERT((fHitRate * std::pow(10, nWeCount)) - std::numeric_limits<uint64_t>::max() <= X_DEFAULT_FLOAT_PRECISION); // 永不溢出
int64_t nHitRateIntHelp = static_cast<uint64_t>(fHitRate * std::pow(10, nWeCount)); // 概率转整数辅助计算
// 根据位数决定随机数范围
int32_t nRandMin = 0;
int32_t nRandMax = std::pow(10, nWeCount);
// 开始测试
auto nTestCount = nTotalCount;
while (nTestCount-- > 0)
{
// 生成随机数
int32_t nRandVal = StdRandEx(nRandMin, nRandMax);
// 命中判定
if (nRandVal < nHitRateIntHelp)
{
nRealHitCount++;
}
}
fRealHitRate = float(nRealHitCount)/float(nTotalCount);
}
void RandomHitTest_std_mt19937(int32_t nTotalCount, float fHitRate, int32_t& nRealHitCount, float& fRealHitRate)
{
nRealHitCount = 0;
fRealHitRate = 0;
if (nTotalCount <= 0 || fHitRate <= 0)
{
return;
}
// 计算浮点小数点个数
int32_t nWeCount = 3; // 位数(三位数,千分比精度)
XASSERT((fHitRate * std::pow(10, nWeCount)) - std::numeric_limits<uint64_t>::max() <= X_DEFAULT_FLOAT_PRECISION); // 永不溢出
int64_t nHitRateIntHelp = static_cast<uint64_t>(fHitRate * std::pow(10, nWeCount)); // 概率转整数辅助计算
// 根据位数决定随机数范围
int32_t nRandMin = 0;
int32_t nRandMax = std::pow(10, nWeCount);
// 设置随机数生成器
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<> dis(nRandMin, nRandMax);
// 重设种子应该使用这个api:::CryptGenRandom
// linux也有相应的高精度随机数
gen.seed(uint32_t(time(NULL)));
// 开始命中测试
auto nTestCount = nTotalCount;
while (nTestCount-- > 0)
{
// 生成随机数
uint32_t randVal = dis(gen);
if (randVal < nHitRateIntHelp)
{
nRealHitCount++;
}
}
fRealHitRate = float(nRealHitCount)/float(nTotalCount);
}
bool RandomHitTest(int32_t nTotalCount, float fHitRate, int32_t nAlgorithmType, int32_t& nRealHitCount, float& fRealHitRate)
{
if (nTotalCount <= 0)
{
return false;
}
bool bRet = true;
switch (nAlgorithmType)
{
case 1:
RandomHitTest_std_rand(nTotalCount, fHitRate, nRealHitCount, fRealHitRate);
break;
case 2:
RandomHitTest_std_mt19937(nTotalCount, fHitRate, nRealHitCount, fRealHitRate);
break;
default:
bRet = false;
break;
}
return true;
}