簡體   English   中英

如何在不使用C ++ 11的情況下使用多個值初始化boost :: mt19937

[英]how to initialize boost::mt19937 with multiple values without using C++11

我可以用:

boost::mt19937 gen(43);   

這工作得很好,但如果我在使用隨機數生成器之前需要超過32位的種子怎么辦? 有沒有一種簡單的方法可以將64位或128位種子放入Mersenne Twister中?

我發現了一些在生成結果之前加載多個值的示例,但沒有一個代碼可以工作。

這段代碼有幾個問題:

std::vector<unsigned int> seedv(1000, 11);
std::vector<unsigned int>::iterator i=seedv.begin();
boost::mt19937 gen2(i, seedv.end());

首先,調用gen2()始終返回相同的值。 我不知道我是怎么搞砸的。

其次,我不想要1000個種子,但是當我將它降低到600時,它會“拋出一個std :: invalid_argument的實例,並在調用種子時注釋足夠的元素”

這種方法可以縮短為少數種子嗎?

這是另一個看起來很簡單的代碼示例:

std::string seedv("thisistheseed");
std::seed_seq q(seedv.begin(),seedv.end());
boost::mt19937 gen2(q);

但它不會編譯。 我終於發現std :: seed_seq僅在c ++ 11中可用。 我堅持使用gcc 4.7,直到我依賴的庫是穩定的。

我想我可以堅持使用32位種子,但我想要更多一點。

我讀過這篇文章: Boost Mersenne Twister:如何使用多個值播種?

我喜歡初始化整個矢量的想法:

mersenne_twister(seed1) ^ mersenne_twister(seed2)

但是如果不修改Mersenne_Twister.hpp,我就沒有辦法做到這一點

有什么建議么?

更新:還有一種方法不做!

unsigned long seedv[4];
seedv[0]=1;
seedv[1]=2;
seedv[2]=3;
seedv[3]=4;
boost::mt19937 gen2(seedv,4);

使用正確的強制轉換,這應該可行,但是我嘗試過的每個強制轉換都不會超過編譯器。 我可以使用C語言進行任何操作,但C ++仍然有時會讓我感到困惑......

使用boost::seed_seq而不是std::seed_seq

更新:使用

boost::random_device rd;
boost::mt19937 eng(rd);

boost::mt19937允許您使用寬度最大為32位的單個值(底層boost::mersenne_twister_enginew參數)或624值的序列(基礎模板的n參數)來boost::mersenne_twister_engine 624是mt19937內部狀態中的元素數。

如果您閱讀文檔,您將看到這兩種機制以不同的方式為引擎狀態設定種子。

  • 使用單個值進行種子設置使用該單個值的復雜函數設置引擎狀態的每個元素。
  • 使用624個值的序列進行種子設定將發動機狀態的每個元素精確地設置為相應的種子值。

關鍵是boost::mt19937本身並不包含將任意數量的種子值映射到其內部狀態中固定數量的元素的機制。 它允許您直接設置狀態(使用624個值),為方便起見,它提供了從單個32位值到完整的624個元素狀態的內置映射。


如果要使用任意數量的輸入種子值,則需要實現從任意大小的序列到624個元素狀態的映射。

請記住,映射的設計應使得生成的內部狀態是mersenne Twister算法的“良好”狀態。 該算法基於移位寄存器,並且可以受到產生相對可預測輸出的內部狀態的影響。 單值的內置映射旨在最大限度地減少此問題,並且您實現的任何內容也應如此。

實現這種映射的最佳方式,而不是自己進行數學分析,可能就是簡單地使用標准的mersenne twister預熱算法。 根據對這個答案的評論,C ++ 11 std::seed_seq被指定執行這樣的預熱。 Boost包括boost::seed_seq ,可能會做同樣的事情。


更新:您可以簡單地使用624個隨機值,而不是使用一些任意數量的值來計算624個值的序列。 如果這些值是無偏的並且均勻分布在32位值的范圍內,那么你就不需要任何預熱(好吧,除非你天文學上不幸)。

boost <random>庫非常直接支持:

boost::random_device rd;
boost::mt19937 eng(rd);

請注意,C ++ 11 <random>庫不支持以這種方式播種。

出於這個原因,存在種子序列生成器助手:

類seed_seq存儲用於播種偽隨機數生成器的32位字序列。 這些單詞將被組合以填充發生器的整個狀態。 http://www.boost.org/doc/libs/1_57_0/doc/html/boost/random/seed_seq.html

#include <boost/random.hpp>
#include <boost/random/seed_seq.hpp>

int main()
{
    boost::random::seed_seq ss({1ul, 2ul, 3ul, 4ul});
    boost::mt19937 gen2(ss);
}

您還可以將一對迭代器傳遞給現有范圍。

住在Coliru

標准Mersenne Twister是以下typedef:

typedef mersenne_twister_engine<uint32_t,32,624,397,31,0x9908b0df, 11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253> mt19937;

第一個模板類型稱為UintType,用作種子方法的參數:

void seed(UIntType value);

因此,您可以使用預定義的boost :: mt19937_64來獲得64位種子。 如果您想更多地定制它,您也可以創建自己的mersenne_twister_engine。

它不漂亮,但應該可以這樣做:

std::vector<unsigned int> seedv(1000);
seedv[0] = 1;
seedv[1] = 2;
seedv[2] = 3;
seedv[3] = 4;
// etc.
boost::mt19937 gen2(seedv.begin(), seedv.end());

也就是說,盡管大多數都是0,但仍傳遞1000粒種子。 但是,正如@ bames53在評論中提到的那樣,這不是一個好主意 它是合法的,並且可以編譯,但不能成為一個好種子。

順便說一句,數組方法應該工作(至少,它應該編譯):

unsigned long seedv[4];
seedv[0]=1;
seedv[1]=2;
seedv[2]=3;
seedv[3]=4;
boost::mt19937 gen2(seedv, seedv + 4);

這是使用指針作為迭代器的示例。 4不是迭代器(通常),但是seedv + 4是(它是seedv結束后元素的地址)。

暫無
暫無

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

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