如何在C++中以高精度生成随机双精度数

How to generate random double numbers with high precision in C++?

本文关键字:随机 双精度 高精度 C++      更新时间:2023-10-16

>我正在尝试以高精度生成许多双随机数系列。例如,0.856365621(小数后有 9 位数字(。

从互联网上找到了一些方法,但是,它们确实会生成双随机数,但精度不如我要求的那么好(小数点后只有 6 位数字(。

因此,我可以知道如何实现我的目标吗?

在 C++11 中,您可以使用 <random> 标头,在此特定示例中使用 std::uniform_real_distribution 我能够生成超过 6 位的随机数。为了查看将通过std::cout打印的位数设置,我们需要使用std::setprecision

#include <iostream>
#include <random>
#include <iomanip>    
int main()
{
    std::random_device rd;
    std::mt19937 e2(rd());
    std::uniform_real_distribution<> dist(1, 10);
    for( int i = 0 ; i < 10; ++i )
    {
       std::cout << std::fixed << std::setprecision(10) << dist(e2) << std::endl ;
    }
    return 0 ;
}

您可以使用std::numeric_limits::digits10来确定可用的精度。

std::cout << std::numeric_limits<double>::digits10 << std::endl;

在典型的系统中,RAND_MAX是 231-1 或类似的东西。因此,使用诸如L之类的方法的"精度">

 double r = rand()/RAND_MAX;

1/(2<sup>31</sup)-1 - 这应该在随机数中为您提供 8-9 位"精度"。确保以足够高的精度打印:

 cout << r << endl;

不行。这将更好地工作:

 cout << fixed << sprecision(15) << r << endl; 

当然,有些系统的RAND_MAX要小得多,在这种情况下,结果可能不那么"精确"——但是,你仍然应该得到 9-12 范围内的数字,只是它们更有可能是"相同的"。

为什么不从随机函数的多次调用中创建你的值呢?

例如:

   const int numDecimals = 9;
   double result = 0.0;
   double div = 1.0;
   double mul = 1.0;
   for (int n = 0; n < numDecimals; ++n)
   {
      int t = rand() % 10;
      result += t * mul;
      mul *= 10.0;
      div /= 10.0;
   }    
   result = result * div;

我个人会尝试兰德函数的新实现,或者至少乘以当前时间或其他东西。

就我而言,我使用的是 MQL5,这是特定市场的非常接近的C++导数,其唯一的随机生成器生成从 0 到 32767 (= (2^15(-1( 的随机整数。精度太低了。

所以我调整了他的想法——随机生成一串我想要的任何长度的数字——来解决我的问题,比我能找到或想到的任何其他东西都更可靠(也可以说更随机(。我的版本构建了一个字符串并在最后将其转换为双精度 - 避免了任何潜在的数学/舍入错误(因为我们都知道0.1 + 0.2 != 0.3 (

将其发布在这里,以防对任何人有帮助。

(免责声明:以下内容是有效的MQL5。MQL5 和 C++ 非常接近,但有一些差异。 例如。没有RAND_MAX常量(所以我对 32767 进行了硬编码(。 我不完全确定所有差异,因此这里可能存在C++语法错误。请相应地调整(。

const int RAND_MAX_INCL = 32767;
const int RAND_MAX_EXCL = RAND_MAX_INCL + 1;
int iRandomDigit() {
    const double dRand = rand()/RAND_MAX_EXCL;  // double 0.0 <= dRand < 1.0
    return (int)(dRand * 10); // int 0 <= result < 10
};
double dRandom0IncTo1Exc(const int iPrecisionDigits) {
    int iPrecisionDigits2 = iPrecisionDigits;
    if ( iPrecisionDigits > DBL_DIG ) { // DBL_DIG == "Number of significant decimal digits for double type"
        Print("WARNING: Can't generate random number with precision > ", DBL_DIG, ". Adjusted precision to ", DBL_DIG, " accordingly.");
        iPrecisionDigits2 = DBL_DIG;
    };
    string sDigits = "";
    for (int i = 0; i < iPrecisionDigits2; i++) {
        sDigits += (string)iRandomDigit();
    };
    const string sResult = "0." + sDigits;
    const double dResult = StringToDouble(sResult);
    return dResult;
}
<小时 />

在对@MasterPlanMan答案的评论中指出 - 其他答案使用为该问题设计的更"官方"方法,来自标准库等。 但是,我认为从概念上讲,当面临其他答案无法解决的限制时,这是一个很好的解决方案。