簡體   English   中英

不止一次播種偽隨機數發生器的問題?

[英]Issues with seeding a pseudo-random number generator more than once?

我已經看到了很多關於每次執行不多次偽隨機數生成器的建議,但從未附帶過徹底的解釋。 當然,很容易理解為什么以下(C / C ++)示例不是一個好主意:

int get_rand() {
  srand(time(NULL));
  return rand();
}

因為每秒多次調用get_rand會產生重復的結果。

但是下面的例子不是一個可以接受的解決方案嗎?

MyRand.h

#ifndef MY_RAND_H
#define MY_RAND_H

class MyRand
{
  public:
    MyRand();
    int get_rand() const;
  private:
    static unsigned int seed_base;
};

#endif

MyRand.cpp

#include <ctime>
#include <cstdlib>
#include "MyRand.h"

unsigned int MyRand::seed_base = static_cast<unsigned int>(time(NULL));

MyRand::MyRand()
{
  srand(seed_base++);
}

int MyRand::get_rand() const
{
  return rand();
}

main.cpp中

#include <iostream>
#include "MyRand.h"

int main(int argc, char *argv[]) 
{
  for (int i = 0; i < 100; i++) 
  {
    MyRand r;
    std::cout << r.get_rand() << " ";
  }
}

即使MyRand :s構造函數快速連續多次調用,每次調用srand都有不同的參數。 顯然,這不是線程安全的,但是也不是rand

每次調用偽隨機數生成器函數時,生成器都會采用某種內部狀態並生成偽隨機數和新的內部狀態。 精心選擇轉換內部狀態的算法,使輸出看起來是隨機的。

當您為隨機數生成器播種時,您基本上是設置此內部狀態。 如果將內部狀態重置為某個可預測值,則會丟失隨機性的外觀。

例如,流行的簡單RNG是線性同余生成器。 數字生成如下:

X[n+1] = (a X[n] + c) mod m

在這種情況下,X [n + 1]既是結果又是新的內部狀態。 如果您按照上面的建議每次播種生成器,您將獲得如下所示的序列:

{(ab + c) mod m, (a(b+1) + c) mod m, (a(b+2) + c) mod m, ...}

其中b是你的seed_base 這根本不是隨機的。

如果你的種子是可預測的,它就在這里,因為你只是遞增它,rand()的輸出也是可預測的。

這實際上取決於你為什么要生成隨機數,以及“隨機”對你來說是一個可接受的隨機數。 在您的示例中,它可以快速連續地避免重復,這對您來說可能已經足夠了。 畢竟,重要的是它運行。

幾乎在每個平台上都有比rand()生成隨機數的更好方法。

嗯,這是額外的處理,不需要做。

在那種情況下,我只是在循環開始之前使用基於時間的種子調用構造函數一次。 這將保證隨機結果,而無需為每次迭代更改種子的額外開銷。

我不認為你的方法比那隨機。

您可以將隨機數生成(這不再是嚴格意義上的實現方式,而是作為說明)作為值表。 如果你記得在統計數據中做任何這樣的東西做簡單的隨機樣本,種子基本上會告訴你在隨機數的大表中開始的行和列。 由於我們已經可以假設數字已經正常分布,因此一次又一次地重新播種是不必要的。

不止一次播種沒有額外的好處,因為這應該足夠好(取決於應用)。 如果確實需要“更多”隨機數,則有許多隨機數生成方法。 我能想到的一個案例是以線程安全的方式生成隨機數。

雖然您的解決方案是可以接受的,但您的數字不會比在全球范圍內播種一次更隨機。 srand一般不應該屬於構造函數。 如果您想支持隨機數,請在程序啟動時播種一次,然后忘記它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM