【问题标题】:rand() function not generating enough randomrand() 函数没有产生足够的随机数
【发布时间】:2013-09-08 23:08:04
【问题描述】:

我正在做一个 openGL 项目,我的 rand 函数没有给我足够大的随机范围。 我的任务是编写一个钻石程序,其中一颗钻石位于屏幕中心,5 颗随机放置在屏幕上的其他位置。正在发生的事情是我的中心钻石在它应该在的位置,而其他五颗正在与中心左侧的一小部分随机排列在一起。我已经包含了绘制菱形的函数。

void myDisplay(void)
{
srand(time(0));

GLintPoint CenterPoint;
int const size = 20;

CenterPoint.x = screenWidth / 2;
CenterPoint.y = screenHeight / 2;

glClear(GL_COLOR_BUFFER_BIT);

drawDiamond(CenterPoint, size);

for (int i = 0; i < 5; i++)
{
    GLfloat x = rand() % 50 + 10;
    GLfloat y = rand() % 200 + 100;
    GLfloat size = rand() % 100;
    GLintPoint diam = {x,y};
    drawDiamond(diam, size);
}

如果需要更多代码,请告诉我,我会编辑。有人对我如何纠正这个有任何想法吗?我已经“玩弄”了 rand() 函数的数字,实际上似乎并没有做太多事情。它们似乎仍然聚集在屏幕上的不同点。我很感激帮助。以防万一有人需要知道,我正在 VS2012 中创建它。

【问题讨论】:

  • 这是大多数伪随机数生成器的问题。它们本质上是非常确定的,要使它们看起来“随机”,您必须提供优质种子。如果您使用 time (NULL) 作为种子同时生成 3 或 4 个进程,它们将生成相同的事件序列。您可以考虑定期重新播种 RNG,使用不同的种子(可能是进程 ID)或两者的某种组合。同样在 rand () 上使用模数实际上会影响结果的质量,您应该将其转换为浮点数并除以 RAND_MAX 并根据您所需的范围进行缩放。
  • 您似乎也没有尝试生成全范围的值。我认为像 GLfloat x = rand() % (screenWidth - 20) + 10; 这样的东西更适合 y 值。除非您的屏幕是 70x400,否则可以解释角落中的集群。
  • @RetiredNinja 我对重复的种子和不均匀的模结果如此着迷,这完全没有引起人们的注意。这是一个优秀的点。

标签: c++ opengl


【解决方案1】:

这与此功能无关:

srand(time(0));

这应该在你的程序开始时调用一次(一个好地方就在main()里面);而且肯定不在您的显示程序中。一旦设置了种子,除非您想重复先前的序列(从外观上看,您不需要),否则您不应再为您的流程再做一次。

也就是说,我强烈建议您使用 C++11 标准库附带的 &lt;random&gt; 中的功能。有了它,您可以建立分布(例如:uniform_int_distribution&lt;&gt;),这些分布将为您完成大部分模数工作,并正确解释此类事情可能遇到的问题(Andon 指出了基于模数的某些数字的可能性)。

花一些时间与&lt;random&gt;。这很值得。使用您正在使用的三个范围的示例:

#include <iostream>
#include <random>
using namespace std;

int main()
{
    std::random_device rd;
    std::default_random_engine rng(rd());

    // our distributions.        
    std::uniform_int_distribution<> dist1(50,60);
    std::uniform_int_distribution<> dist2(200,300);
    std::uniform_int_distribution<> dist3(0,100);

    for (int i=0;i<10;++i)
        std::cout << dist1(rng) << ',' << dist2(rng) << ',' << dist3(rng) << std::endl;

    return EXIT_SUCCESS;
}

输出(明显不同)。

58,292,70
56,233,41
57,273,98
52,204,8
50,284,43
51,292,48
53,220,42
54,281,64
50,290,51
53,220,7

是的,就是这么简单。就像我说的,那个图书馆就是这只猫的睡衣。它提供了许多更多的东西,包括随机正态分布、不同的引擎后端等。我强烈建议您检查一下。

【讨论】:

    【解决方案2】:

    正如 WhozCraig 所提到的,每次调用 myDisplay (...) 时都在随机数生成器中播种是一个坏主意。这是因为time (NULL) 的粒度为 1 秒,而在实时图形中,您通常每秒绘制一次以上的场景。因此,每次调用 myDisplay (...) 时不到 1 秒,您都在重复相同的随机数序列。

    此外,对rand (...) 的调用使用模运算会对返回值的质量产生不利影响。这是因为它改变了数字出现的概率分布。首选技术应该是将 rand (...) 转换为浮点数,然后除以 RAND_MAX,然后将此结果乘以您想要的范围。

    GLfloat x = rand() % 50 + 10; /* <-- Bad! */
    
    /* Consider this instead */
    GLfloat x = (GLfloat)rand () / RAND_MAX * 50.0f + 10.0f;
    

    不过,想想吧。如果要在 2 行之后将 x 和 y 存储在整数数据结构中,为什么还要使用 GLfloat

    【讨论】:

      猜你喜欢
      • 2017-03-28
      • 1970-01-01
      • 2018-05-15
      • 1970-01-01
      • 2015-09-29
      • 2011-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多