而不是随机的——选择

srand not random at all - alternatives?

本文关键字:选择 随机      更新时间:2023-10-16

我在玩弄数组,用伪随机数填充,找到最小值和最大值及其索引和出现次数,我注意到一些奇怪的东西- 当使用srand随时间播种时,最小值和最大值出现的次数总是等于。这对我来说不是很随意。

是否有一种替代方法可以获得不同数量的最小值和最大值,正如人们期望的随机数一样?

这是我的代码(我正在学习,所以它可能是混乱和低效的,欢迎建议)

#include <cstdlib>
#include <iostream>
#include <time.h>
using namespace std;
void findExtremes( const int[], int); 
int main()
{
    const int lenght = 2000; //define lenght
    int array1[lenght];
    srand(time(0)); 
    for ( int i = 0; i < lenght; i++) //populate array with random numbers and print them out
    {
        array1[i] = rand() % 3000;
        cout << "Index " << i << " = " << array1[i] << endl;
    }
    findExtremes(array1, lenght);   // call fn
    return 0;
}
void findExtremes( const int array[], int size)
{
     int maxV, minV, maxI, minI;
     maxV = array[0];
     minV = array[0];
     minI = 0;
     maxI = 0;
     for ( int i = 1; i < size; i++)
     {
         if ( array[i] > maxV)
            {
                maxV = array[i];
                maxI = i;
            }
         if ( array[i] < minV)
            {
                minV = array[i];
                minI = i;
            }
     }
     //find the number of occurances for min and max values
     int minOcc = 0;
     int maxOcc = 0;
     for ( int i = 1; i < size; i++)
     {
             if (array[i] == minV)
                 minOcc++;
             if (array[i] == minV)
                 maxOcc++;
     }
     //output
     cout << "nMinmim value is index " << minI << " with value " << minV << " and " << minOcc << " occurances" << endl;
     cout << "nMaxium value is index " << maxI << " with value " << maxV << " and " << maxOcc << " occurances" << endl << "n";  
}

首先,它们实际上是随机数,而不是随机数。在任何情况下,可能是一个真正的随机序列具有你所看到的确切属性:-)序列1,1,1,1,15,2,4,2,99一样有可能出现在一个真正的随机集合中。

如果你想要一个"更随机"的随机序列,我不会使用C库附带的正常序列(除非这些库是由理解随机性的人编写的)-你应该看看像Mersenne Twister这样的东西,使用/dev/random(如果在Linux下)等等。

您可能还想看看这段代码。

if (array[i] == minV)
    minOcc++;
if (array[i] == minV)
    maxOcc++;

我认为最后的if应该与maxV比较,而不是与minV比较。否则,您的最小和最大计数不相同的可能性为零。

当我进行更改(并将% 3000更改为% 30,以获得重复的范围)时,我看到:

Minmim value is index 112 with value 0 and 65 occurances
Maxium value is index 24 with value 29 and 58 occurances

而且,就这个问题而言,这并不重要,您可能需要稍微清理一下您的拼写:

  • lenght -> length .
  • minmum -> minimum
  • maxium -> maximum
  • occurances -> occurrences

我对物理进行数值模拟,我的小组使用GSL库进行模拟:

#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
class Random
{
private:
    gsl_rng* r; //!< Pointer to the gsl rng
public:
    //! Constructor: uses argument as the seed
    Random(long unsigned int seed);
    long int R(int N);
    long double R();
    long double gaussianR(long double sigma);
};
inline Random::Random(long unsigned int s)
{
    r = gsl_rng_alloc( gsl_rng_taus );
    gsl_rng_set(r, s); //seed to use to the pseudo-aleatory number generator.
}
// a uniform number between 0 and N-1
inline long int Random::R(int N)
{
    return gsl_rng_uniform_int (r, N);
}
// a uniform number between 0 and 1
inline long double Random::R()
{
    return gsl_rng_uniform_pos( r );
}
// a gaussian distribution with sigma
inline long double Random::gaussianR(long double sigma)
{
    return gsl_ran_gaussian(r, sigma);
}

你必须用flags来编译:OTHER_LDFLAGS = -lgsl -lm -lgslcblas

和添加包含和库(这是fink安装情况):

HEADER_SEARCH_PATHS =/sw/includeLIBRARY_SEARCH_PATHS =/sw/lib

希望这对你有帮助。

您可以使用c++ 11中包含的新的random库,或者您可以使用它所基于的Boost::Random库。

您的伪随机数生成器(PRNG)的行为完全正常。

事实上,如果你从rand()中抽取足够的数字,你将总是得到相同的极值,因为它是均匀分布的。

在您的情况下,问题是:您是否需要另一个行为?你不应该像@sehe建议的那样突然攻击真实随机数。这可能是无用的,甚至在处理随机模拟时,蒙特卡罗算法是有问题的。想象一下,您想要调试一个基于随机数的代码片段,或者您的同事想要检查您的结果:如果您无法重现相同的随机序列,您该怎么办?

这就是为什么当你不需要加密安全的随机数时,prng是足够的,并且通常是首选的原因之一。

我认为问题是你最初的陈述是错误的。代码是每次提供不同的数字。我尝试了未修改的代码,结果如下:

Minmim value is index 1194 with value 0 and 1 occurances
Maxium value is index 1264 with value 2995 and 1 occurances
Minmim value is index 1958 with value 1 and 1 occurances
Maxium value is index 1510 with value 2991 and 1 occurances
...

但是,代码中有两个错误:

    在第二个for循环中,你应该从i = 0开始。
  • 你应该在同一个循环中比较maxV而不是minV。

关于随机数的生成:

  • 当使用相同的数字播种时,系列rand()调用应该返回相同的数字。Rand()不是用于随机数,而是用于伪随机数。Rand()应该有这种方式,因为例如,当以相同的种子开始时,模拟将输出相同的结果。这是一个非常好的属性。
  • 您将用当前时间作为种子,这是可以的,因此rand()每次都应该返回一个不同的数字序列(至少在一秒钟内没有调用多次时)。我看播种情况不错。实际上,它与这里提供的示例非常相似。
  • 样本量为2000,生成的数字范围为3000。这意味着最小尺寸和最大尺寸不可能总是相同的。如果样本量是100万,那么2999很有可能是大多数运行中最大的数字。

Gentlepeople:注意

是的!这个答案是"老"的。在c++11时代,一定要使用c++11 <random>。但是不要在事实发生多年后,因为你认为"Ew每个人都知道 rand()是邪恶的!"而否决这个问题。事实上,并非如此。它是有限的,而且很容易使用不当。但是 -作为一个历史事实,它作为一个API存在,并且仍然有用的文档说明如何更好地使用。我不删除这个答案是有原因的。

原始回答:


请阅读http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx

注意,不要写rand() % 3000。写

 int r = rand() / ( RAND_MAX / 3000 + 1 );

事实上,随机应该是均匀分布的,这意味着当样本数量足够大(对于初学者来说,大于域的大小)时,下限和上限确实有接近100%的机会发生。

这就是真正的随机(尝试在没有它的情况下做蒙特卡罗算法-你会非常不高兴)