2011-02-16 182 views
2

我知道C++中的隨機數生成有一些限制(可以是非均勻的)。我怎樣才能從1到14620產生一個數字?隨機數發生器,C++

謝謝。

+0

你現在連仰望如何在C++中使用隨機數?你也沒有說明你是否需要一個更好的解決方案來建立在C++中的隨機數字或者只是被告知如何使用rand。 – thecoshman 2011-02-16 17:28:33

+0

你能澄清一下你的意思是「針對隨機數生成的限制」,特定於C++嗎?或多或少均勻的序列來自更好或更差的發生器。 – Francesco 2011-02-16 18:18:09

+0

如果rand()是(可以是非均勻的),那麼它沒有多大用處。 – 2011-02-16 18:21:40

回答

17

一種常見的方法是使用std::rand()與模:

#include<cstdlib> 
#include<ctime> 

// ... 
std::srand(std::time(0)); // needed once per program run 
int r = std::rand() % 14620 + 1; 

然而,隨着@tenfour在他的回答中提到,模運算符可以破壞值std::rand()回報的均勻性。這是因爲模數將它丟棄的值轉換爲有效值,並且這種轉換可能不一致。例如,對於[0,10]中的n,值n % 9將9轉換爲0,因此您可以通過將真零或9轉換爲零來獲得零。其他值只有一個機會產生。

另一種方法是將隨機數從std::rand()轉換爲[0,1]範圍內的浮點值,然後轉換並將值移動到您希望的範圍內。

int r = static_cast<double>(std::rand())/RAND_MAX * 14620 + 1; 
4

使用rand

(rand() % 100) is in the range 0 to 99 
(rand() % 100 + 1) is in the range 1 to 100 
(rand() % 30 + 1985) is in the range 1985 to 2014 

(rand() % 14620 + 1) is in the range 1 to 14620 

編輯:

爲鏈接提到的,隨機使用前應進行使用srand接種。使用一個共同的獨特價值是致電time的結果。

11

srand()/rand()是你所需要的功能的教程,正如其他人回答。

%的問題在於結果顯然是不均勻的。爲了說明,假設rand()返回0-3的範圍。以下是稱這是4000倍的假設結果:

0 - 1000 times 
1 - 1000 times 
2 - 1000 times 
3 - 1000 times 

現在,如果你對(rand() % 3)做同樣的取樣,你會發現結果會是這樣:

0 - 2000 times 
1 - 1000 times 
2 - 1000 times 

哎喲!更均勻的溶液是這樣的:

int n = (int)(((((double)std::rand())/RAND_MAX) * 14620) + 1);

對不起,草率的代碼,但這個想法是正確比例縮小到你想要使用浮點運算的範圍內,並轉換爲整數。

18

如果你有一個C++ 0x中的環境,升壓11b的接近衍生物爲現在的標準:

#include <random> 
#include <iostream> 

int main() 
{ 
    std::uniform_int_distribution<> d(1, 14620); 
    std::mt19937 gen; 
    std::cout << d(gen) << '\n'; 
} 

這將是快速,方便和高品質。

你沒有指定,但如果你想浮點,而不是僅僅在子:

std::uniform_real_distribution<> d(1, 14620); 

如果你需要一個非均勻分佈,你可以建立自己的分段常數或piece-明智的線性分佈很容易。

1

如前所述,您可以使用rand()。例如。

int n = rand() % 14620 + 1;

做的工作,但它是不均勻的。 這意味着一些值(低值)會稍微頻繁出現。這是因爲rand()產生的值在0到RAND_MAX之間,而RAND_MAX通常不能被14620整除。如果是RAND_MAX == 15000,那麼數字1將是數字1000的兩倍,因爲rand() == 0rand() == 14620都產生n==1,但只有rand()==999使得n==1000爲真。

但是,如果14620比RAND_MAX小得多,這種影響可以忽略不計。在我的電腦RAND_MAX等於2147483647.如果rand()產生介於0和RAND_MAX之間的均勻樣本,那麼因爲2147483647%14620 = 10327和2147483647/14620 = 146886,所以n平均146887次會在1和10328之間,而10329和10329之間的數字如果您繪製2147483647個樣本,則平均146886次會發生。 如果你問我,沒什麼區別。

但是,如果RAND_MAX == 15000它將有所不同,如上所述。 在這種情況下,一些較早的帖子建議使用

int n = (int)(((((double)std::rand())/RAND_MAX) * 14620) + 1);

,使其「更加均勻」。 請注意,由於rand()仍然只返回「僅」RAND_MAX不同值,因此這隻會更改頻繁發生的數字。 爲了使它真的一致,如果它在14620 * int(RAND_MAX/14620)和RAND_MAX之間的範圍內並且再次呼叫rand(),則必須拒絕任何整數形式rand()。 在RAND_MAX == 15000的示例中,您將拒絕14620和15000之間的rand()的任何值並再次繪製。 對於大多數應用程序來說,這不是必需的。我更擔心rand()的隨機性。

0

模運算符是最重要的,你可以申請限制,從而與此模量,檢查了這一點:

// random numbers generation in C++ using builtin functions 
#include <iostream> 

using namespace std; 

#include <iomanip> 

using std::setw; 

#include <cstdlib> // contains function prototype for rand 

int main() 
{ 
// loop 20 times 
for (int counter = 1; counter <= 20; counter++) { 

    // pick random number from 1 to 6 and output it 
    cout << setw(10) << (1 + rand() % 6); 

    // if counter divisible by 5, begin new line of output 
    if (counter % 5 == 0) 
     cout << endl; 

} 

return 0; // indicates successful termination 

} // end main 
1

的rand()函數是不是真的是最好的隨機數生成器,一個更好的方式是通過使用CryptGenRandom()。

這個例子應該做的伎倆:

#include <Windows.h> 

// Random-Generator 
HCRYPTPROV hProv; 
INT Random() { 
    if (hProv == NULL) { 
     if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) 
      ExitProcess(EXIT_FAILURE); 
    } 

    int out; 
    CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out)); 
    return out & 0x7fffffff; 
} 

int main() { 
    int ri = Random() % 14620 + 1; 
}