C++从0到最大长整数获取随机数

Ngu*_*ong 0 c++

我有以下功能:

typedef unsigned long long int UINT64;
UINT64 getRandom(const UINT64 &begin = 0, const UINT64 &end = 100) {
    return begin >= end ? 0 : begin + (UINT64) ((end - begin)*rand()/(double)RAND_MAX);
};
Run Code Online (Sandbox Code Playgroud)

每当我打电话

getRandom(0, ULLONG_MAX);
Run Code Online (Sandbox Code Playgroud)

要么

getRandom(0, LLONG_MAX);
Run Code Online (Sandbox Code Playgroud)

总是得到相同的价值562967133814800.我该如何解决这个问题?

Ric*_*ard 17

什么是rand()

根据rand()函数返回范围内的值[0,RAND_MAX].

什么是RAND_MAX

根据这个,RAND_MAX是"一个整数常量表达式,其值是rand函数返回的最大值.该值与库有关,但在任何标准库实现上保证至少为32767."

精确是一个问题

您可以使用rand()/(double)RAND_MAX,但您可能只有32767个离散值.因此,虽然你的数字很大,但实际上并没有更多的数字.这可能是一个问题.

播种可能是一个问题

另外,您不会谈论如何调用该函数.你是否运行该程序一次LLONG_MAX,另一次用ULLONG_MAX?在这种情况下,您看到的行为是因为您每次都隐式使用相同的随机种子.换句话说,每次运行程序时,它都会生成完全相同的随机数序列.

我该如何种子?

你可以使用这样的srand()功能:

#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */

int main (){
  srand (time(NULL));
  //The rest of your program goes here
}
Run Code Online (Sandbox Code Playgroud)

现在,每次运行程序时,您都会得到一个新的随机数序列.

溢出是一个问题

考虑这部分((end - begin)*rand()/(double)RAND_MAX).

什么是(end-begin)?根据定义,它是LLONG_MAX或者ULLONG_MAX这些数据类型可以容纳的最大可能值.因此,将它们乘以任何东西都是不好的.但你做到了!你将它们乘以rand(),这是非零.这会导致溢出.但我们可以解决这个问题......

运营秩序是一个问题

然后你将它们除以RAND_MAX.我认为你的操作顺序错了.你真的想说:

((end - begin) * (rand()/(double)RAND_MAX) )
Run Code Online (Sandbox Code Playgroud)

注意新的parantheses!(rand()/(double)RAND_MAX)

现在您将整数乘以一个分数,因此您可以保证不会溢出.但这引入了一个新问题......

促销是一个问题

但是还有一个更深层次的问题.你将int除以double.当你做的int提升到一个double.双精度是一个浮点数,这基本上意味着它牺牲精度以获得范围.那可能就是在咬你.当你获得越来越大的数字时,你ullong和你的llong最终都会被投射到相同的值.如果您首先溢出数据类型(见上文),则尤其如此.

哦,哦

所以,基本上,你提出的关于PRNG的一切都是错误的.

也许这就是John von Neumann所说的原因

任何试图通过确定性手段产生随机数的人当然都处于犯罪状态.

而且,有时,我们为这些罪行买单.

我怎么能自己解脱?

C++ 11提供了一些不错的功能.您可以按如下方式使用它

#include <iostream>
#include <random>
#include <limits>
int main(){
  std::random_device rd;     //Get a random seed from the OS entropy device, or whatever
  std::mt19937_64 eng(rd()); //Use the 64-bit Mersenne Twister 19937 generator
                             //and seed it with entropy.

  //Define the distribution, by default it goes from 0 to MAX(unsigned long long)
  //or what have you.
  std::uniform_int_distribution<unsigned long long> distr;

  //Generate random numbers
  for(int n=0; n<40; n++)
    std::cout << distr(eng) << ' ';
  std::cout << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

(请注意,适当播种发电机很困难.这个问题可以解决这个问题.)

  • 这是我见过的最完整的答案之一.我测试了代码,它的工作原理.做得好! (2认同)