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

4

我想要生成一系列高精度的双精度随机数。例如,0.856365621(小数点后有9位数字)。

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

请问如何实现我的目标?


2
你可以演示一下你尝试过的方法,这样我们就知道你都试了什么。 - Shafik Yaghmour
3
你确定你不只是使用默认的六个数字精度来打印这些数字吗? - Useless
https://dev59.com/C3M_5IYBdhLWcg3whzrx - Robert Harvey
你需要52个随机位来实现完整的双精度,因此你需要一个至少具有这么大的伪随机数生成器(PRNG),否则你将不得不调用多次较小的PRNG才能获得至少52位的值,然后你可以直接进行除法或将位移动到双精度值中。 - Lee Daniel Crocker
生成随机双精度数通常会带来问题。在0.25和0.5之间的双精度数与在0.5和1.0之间的双精度数一样多。获取结果x的机会是否应该取决于值x的大小?如果不是,那么在0.25和0.5之间获得结果的机会将等于在0.5和1之间获得结果的机会。 - MSalters
已经有一段时间了,我很好奇你是否有任何问题或者我的回答是否已经涵盖了所有内容。 - Shafik Yaghmour
4个回答

5

在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;

我也有类似的问题在这里。如果可能的话,你能帮我解决吗? - user1950349

1
在一个典型的系统中,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位数字,只是它们更有可能相同。

-1
在我的情况下,我正在使用MQL5,这是C++的一个非常接近的衍生版本,用于特定市场,其唯一的随机生成器产生从0到32767(=(2 ^ 15)-1)的随机整数。精度远远不够。
因此,我改编了他的想法--随机生成任意长度的数字字符串--来解决我的问题,比我能找到或想到的任何其他方法更可靠(并且可以说更随机)。我的版本在最后构建一个字符串并将其转换为double--避免了沿途任何潜在的数学/舍入错误(因为我们都知道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's answer 的评论中指出——其他答案使用了更多“官方”方法,如标准库等。然而,我认为从概念上讲,当面临其他答案无法解决的限制时,这是一个很好的解决方案。

不需要创建一个字符串(代价高、奇怪),你可以通过进行一些数学计算来获得更高的精度。例如,类似 rand()/32768 + rand()/(32768*32768) 的内容。 - Joe C.
@Joe C.确实如此。但你真的尝试过吗?我探索了各种不同的数学选项(包括你的例子),但它们并不能提供均匀分布的结果。这就像反复掷两个骰子会产生比二或十二更多的七一样。上面的方法保证是均匀分布的。不确定你是否是那个点踩者。如果是,也许你可以重新考虑一下。 - DavidT
还有更好的选择,比如说,你可以在两个rand()调用之间做一些类似这样的事情:重复(rand()%10)次:rand(),这将使事情变得更加有趣。 - Joe C.
@Joe C. 上下文:我提到我尝试了很多数学可能性,但失败了。但我并不感到太惊讶。因为我已经忘记了大部分大学数学统计知识,因为那是很多年前的事情了,但我仍然相信,任何试图将rand()函数的加法/乘法组合起来的努力都会使结果偏离均匀分布(就像骰子的例子一样)。此外,几乎所有语言中的rand()函数都只是伪随机数生成器,而逐位方法也可以缓解这种情况。我并不是说这种方法是万能的,只是一个确实有效的选项... - DavidT
(在逻辑上和实践中)并且确实可靠地解决了这些问题,因此适用于其他答案无法使用的情况。我说了这些之后,很抱歉,我真的没有理解你的例子。您是否有一种数值/数学方法,可以确定解决这些问题?您能发布一些经过测试的实际代码吗?除非您提出一种替代的逐位方法,即将每个数字乘以连续的10的幂,而不是将它们连接为字符串...?如果是这样,那基本上就是@MasterPlanMan的答案了...?应该可以工作。它在本质上有什么更好的地方吗? - DavidT

-1
为什么不通过多次调用随机函数来创建您的价值呢?
例如:
   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;

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

1
我能理解为什么这个回答会被投票否决,因为其他的回答使用了更多“官方”方法,比如标准库等。然而,我投了赞成票,因为我正在使用MQL5,这是C++的一个衍生版本,其唯一的随机生成器函数只能产生从0到32767(=(2^15)-1)的随机整数。这太低了。所以我采用了这个想法——随机生成任意长度的数字字符串——来解决我的问题,比我能找到或想到的任何其他方法都更可靠(也可以说更随机)。如果有帮助,我将把我的解决方案发布为答案。 - DavidT

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接