Error

C++博客 首页 新随笔 联系 聚合 管理
  217 Posts :: 61 Stories :: 32 Comments :: 0 Trackbacks
// 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<floatfloat>> 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<floatfloat> tupleResult = std::make_tuple(fHitRate, std::fabsf(fRealHitRate1 - fRealHitRate));
            vecResult.push_back(tupleResult);
        }
    }

    std::sort(vecResult.begin(), vecResult.end(), 
        [](std::tuple<floatfloat>& tupLeft, std::tuple<floatfloat>& 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;
}

posted on 2017-01-22 12:28 Enic 阅读(780) 评论(0)  编辑 收藏 引用 所属分类: 从零开始写棋牌游戏平台

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理