パフォーマンスが重要なパスでランダムなブール値を生成する必要があります。
このために書いたコードは
_std::random_device rd;
std::uniform_int_distribution<> randomizer(0, 1);
const int val randomizer(std::mt19937(rd()));
const bool isDirectionChanged = static_cast<bool>(val);
_
しかし、これが_static_cast<bool>
_を行うのが好きではないので、これがこれを行う最良の方法だとは思わないでください。
ウェブ上でさらにいくつかの解決策を見つけました
1。 _std::bernoulli_distribution
_
2。bool randbool = Rand() & 1;
最初にsrand()
を呼び出すことを忘れないでください。
パフォーマンスのために、たとえば「ランダム性」よりも低い価格で。 std::mt19937_64
、 Xorshift + を使用して64ビットの数値を生成し、それらの数値のビットを擬似乱数ブールとして使用できます。
ウィキペディアを引用:
このジェネレーターは、BigCrushを渡す最速のジェネレーターの1つです。
詳細: http://xorshift.di.unimi.it/ ページの中央に比較表があり、mt19937_64
は2倍遅く、系統的です。
以下にサンプルコードを示します(実際のコードはクラスにラップする必要があります)。
#include <cstdint>
#include <random>
using namespace std;
random_device rd;
/* The state must be seeded so that it is not everywhere zero. */
uint64_t s[2] = { (uint64_t(rd()) << 32) ^ (rd()),
(uint64_t(rd()) << 32) ^ (rd()) };
uint64_t curRand;
uint8_t bit = 63;
uint64_t xorshift128plus(void) {
uint64_t x = s[0];
uint64_t const y = s[1];
s[0] = y;
x ^= x << 23; // a
s[1] = x ^ y ^ (x >> 17) ^ (y >> 26); // b, c
return s[1] + y;
}
bool randBool()
{
if(bit >= 63)
{
curRand = xorshift128plus();
bit = 0;
return curRand & 1;
}
else
{
bit++;
return curRand & (1<<bit);
}
}
いくつかの簡単なベンチマーク( code ):
647921509 RandomizerXorshiftPlus
821202158 BoolGenerator2 (reusing the same buffer)
1065582517 modified Randomizer
1130958451 BoolGenerator2 (creating a new buffer as needed)
1140139042 xorshift128plus
2738780431 xorshift1024star
4629217068 std::mt19937
6613608092 Rand()
8606805191 std::bernoulli_distribution
11454538279 BoolGenerator
19288820587 std::uniform_int_distribution
すぐに使用できるコードが必要な場合は、XorShift128PlusBitShifterPseudoRandomBooleanGenerator
、上記のリンクからのRandomizerXorshiftPlus
の微調整バージョン。私のマシンでは、@ SergeRogatchのソリューションとほぼ同じ速度ですが、ループカウントが高い(≳100,000)場合は常に約10〜20%速く、ループカウントが小さい場合は最大約30%遅くなります。
class XorShift128PlusBitShifterPseudoRandomBooleanGenerator {
public:
bool randBool() {
if (counter == 0) {
counter = sizeof(GeneratorType::result_type) * CHAR_BIT;
random_integer = generator();
}
return (random_integer >> --counter) & 1;
}
private:
class XorShift128Plus {
public:
using result_type = uint64_t;
XorShift128Plus() {
std::random_device rd;
state[0] = rd();
state[1] = rd();
}
result_type operator()() {
auto x = state[0];
auto y = state[1];
state[0] = y;
x ^= x << 23;
state[1] = x ^ y ^ (x >> 17) ^ (y >> 26);
return state[1] + y;
}
private:
result_type state[2];
};
using GeneratorType = XorShift128Plus;
GeneratorType generator;
GeneratorType::result_type random_integer;
int counter = 0;
};
方法は、コメントに記載されているように、64回のランダム呼び出しごとにunsigned long long
を生成するだけです。例:
#include <random>
class Randomizer
{
public:
Randomizer() : m_Rand(0), counter(0), randomizer(0, std::numeric_limits<unsigned long long>::max()) {}
bool RandomBool()
{
if (!counter)
{
m_Rand = randomizer(std::mt19937(rd()));
counter = sizeof(unsigned long long) * 8;
}
return (m_Rand >> --counter) & 1;
}
private:
std::random_device rd;
std::uniform_int_distribution<unsigned long long> randomizer;
unsigned long long m_Rand;
int counter;
};
64ビットのランダム値の(十分な長さの)(循環)バッファを事前に入力し、ブールのランダム値が必要なときに一度に1ビットずつ非常に迅速に取得します
#include <stdint.h>
class BoolGenerator {
private:
const int BUFFER_SIZE = 65536;
uint64_t randomBuffer[BUFFER_SIZE];
uint64_t mask;
int counter;
void advanceCounter {
counter++;
if (counter == BUFFER_SIZE) {
counter = 0;
}
}
public:
BoolGenerator() {
//HERE FILL YOUR BUFFER WITH A RANDOM GENERATOR
mask = 1;
counter = 0;
}
bool generate() {
mask <<= 1;
if (!mask) { //After 64 shifts the mask becomes zero
mask = 1;//reset mask
advanceCounter();//get the next value in the buffer
}
return randomBuffer[counter] & mask;
}
}
もちろん、このクラスは、バッファサイズ、ランダムジェネレータ、ベースタイプ(必ずしもuint64_tである必要はありません)などに対して一般的にすることができます。
64回の呼び出しごとに1回だけバッファーにアクセスします。
#include <stdint.h> //...and much more
class BoolGenerator {
private:
static const int BUFFER_SIZE = 65536;
uint64_t randomBuffer[BUFFER_SIZE];
uint64_t currValue;
int bufferCounter;
int bitCounter;
void advanceBufferCounter() {
bufferCounter++;
if (bufferCounter == BUFFER_SIZE) {
bufferCounter = 0;
}
}
void getNextValue() {
currValue = randomBuffer[bufferCounter];
bitCounter = sizeof(uint64_t) * 8;
advanceBufferCounter();
}
//HERE FILL YOUR BUFFER WITH A RANDOM GENERATOR
void initializeBuffer() {
//Anything will do, taken from here: http://stackoverflow.com/a/19728404/2436175
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<uint64_t> uni(0,std::numeric_limits<uint64_t>::max());
for (int i = 0; i < BUFFER_SIZE; i++ ) {
randomBuffer[i] = uni(rng);
}
}
public:
BoolGenerator() {
initializeBuffer();
bufferCounter = 0;
getNextValue();
}
bool generate() {
if (!bitCounter) {
getNextValue();
}
//A variation of other methods seen around
bitCounter--;
bool retVal = currValue & 0x01;
currValue >>= 1;
return retVal;
}
};
必要なランダム性にさらに制約がない限り、ランダムboolを生成する最も速い方法は次のとおりです。
bool RandomBool() { return false; }
具体的には、ランダムなブール値を生成する数千の方法があり、すべてがさまざまな制約を満たしますが、その多くは「これまでのすべての答えを含む」「真の」乱数を提供しません。 「ランダム」という言葉だけでは、本当に必要なプロパティは誰にもわかりません。
パフォーマンスが唯一の基準である場合、 answer は次のとおりです。
bool get_random()
{
return true; // chosen by fair coin flip.
// guaranteed to be random.
}
残念ながら、この乱数のエントロピーはゼロですが、パフォーマンスは非常に高速です。
この乱数ジェネレーターはあまり役に立たないと思われるので、ブール値をどの程度ランダムにするかを定量化する必要があります。 2048のサイクル長はどうですか? 100万? 2 ^ 19937-1?宇宙の終わりまで?
パフォーマンスが最大の関心事であると明示的に述べているので、古き良き線形合同ジェネレータは「十分」であると思われます。 この記事 に基づいて、このジェネレーターの周期は約32 *((2 ^ 31)-5)、つまり約68兆回の反復であると推測しています。それが「十分」でない場合は、minstd_Randの代わりに任意のC++ 11互換ジェネレーターをドロップできます。
余分なクレジットと小さなパフォーマンスヒットについては、以下のコードを変更して biased coin algorithm を使用し、ジェネレーターのバイアスを削除します。
#include <iostream>
#include <random>
bool get_random()
{
typedef std::minstd_Rand generator_type;
typedef generator_type::result_type result_type;
static generator_type generator;
static unsigned int bits_remaining = 0;
static result_type random_bits;
if ( bits_remaining == 0 )
{
random_bits = generator();
bits_remaining = sizeof( result_type ) * CHAR_BIT - 1;
}
return ( ( random_bits & ( 1 << bits_remaining-- ) ) != 0 );
}
int main()
{
for ( unsigned int i = 0; i < 1000; i++ )
{
std::cout << " Choice " << i << ": ";
if ( get_random() )
std::cout << "true";
else
std::cout << "false";
std::cout << std::endl;
}
}
最善の方法は、事前に計算されたランダム配列を使用することだと思います。
uint8_t g_Rand[UINT16_MAX];
bool InitRand()
{
for (size_t i = 0, n = UINT16_MAX; i < n; ++i)
g_Rand[i] = ::Rand() & 1;
return true;
}
bool g_inited = InitRand();
inline const uint8_t * Rand()
{
return g_Rand + (::Rand()&INT16_MAX);
}
配列dst [size]を埋めるために使用します:
const size_t size = 10000;
bool dst[size];
for (size_t i = 0; i < size; i += INT16_MAX)
memcpy(dst + i, Rand(), std::min<size_t>(INT16_MAX, size - col));
もちろん、別のランダム関数を使用して、事前に計算された配列を初期化できます。
どうやら私は別の答えを追加する必要があります。 Ivy Bridge アーキテクチャで始まるIntelが RdRand CPU命令を追加し、AMDが2015年6月にそれを追加したことを理解しただけです。 (インライン)アセンブリを使用しても構いません。ランダムなbool
sを生成する最速の方法は、RdRand
CPU命令を呼び出して64ビットの乱数を取得することです here =(コード例についてはページのほぼ中央までスクロールします)(そのリンクには、現在のCPUでRdRand命令のサポートを確認するコード例もあります。また、CPUIDでこれを行う方法については、Wikipediaを参照してくださいそして、私の Xorshit +ベースの回答 で説明されているように、ブール値にその数のビットを使用します。
パフォーマンスが重要な場合は、おそらく32ビットの乱数を生成し、そのビットを個別に使用することをお勧めします。次のようなものです。
bool getRandBool() {
static uint32_t randomnumber;
static int i=0;
if (i==0) {
randomnumber = <whatever your favorite randonnumbergenerator is>;
i=32;
}
return (randomnumber & 1<<--i);
}
このように、世代は32番目の呼び出しごとにのみ影響します