web-dev-qa-db-ja.com

C ++用の高速ランダムジェネレーターが必要

ユークリッド距離のTSPジェネレーターでopt-3スワップを実行しようとしていますが、多くの場合〜500以上のノードがあるため、スワップを試行する3つのノードのうち少なくとも1つをランダムに選択する必要があります。

したがって、基本的にはfastである乱数関数が必要です。 (通常のRand()はあまりにも遅いです)すばらしくする必要はなく、ちょうど良い十分な

編集:私は言及するのを忘れました、私は標準言語ライブラリ(STL、iostreamなど)以外のライブラリを追加できない環境に座っています。ブーストなし= /

44

他のスレッドはMarsagliaのxorshfジェネレーターについて言及しましたが、誰もコードを投稿していません。

static unsigned long x=123456789, y=362436069, z=521288629;

unsigned long xorshf96(void) {          //period 2^96-1
unsigned long t;
    x ^= x << 16;
    x ^= x >> 5;
    x ^= x << 1;

   t = x;
   x = y;
   y = z;
   z = t ^ x ^ y;

  return z;
}

私はこれをあちこちで使用しました。失敗した唯一の場所は、ランダムバイナリマトリックスを生成しようとしたときでした。約95x95のマトリックスを過ぎると、生成される特異マトリックスの数が少なすぎるか、または多すぎます(どれを忘れるか)。このジェネレータは、線形シフトフィードバックレジスタと同等であることが示されています。しかし、暗号化や深刻なモンテカルロ作業を行わない限り、このジェネレーターは揺れ動きます。

62
AndyV

インテルのサイトからの2つの優れた選択肢:

1)fastrand-std Rand()より2.01倍高速です。このルーチンは、C libと同様の出力値範囲の整数を1つ返します。

inline int fastrand() { 
  g_seed = (214013*g_seed+2531011); 
  return (g_seed>>16)&0x7FFF; 
} 

2)SSEバージョン(以下のリンクを参照)は、std Rand()の約5.5倍の速度ですが、一度に4つのランダムな値を生成し、sseを持つプロセッサが必要です(ほとんどすべて) 、より複雑です。

http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/

28
Sunsetquest

これらのジェネレーター 乱数ジェネレーターの専門家George Marsagliaから参照してください。それらはCマクロとして実装されており、非常に高速で、生成される数ごとにわずかな操作しかありません。

12
John D. Cook

Mersenne Twister にはいくつかの高速な実装があります。

6
lhf

Ivy Bridge アーキテクチャで始まるIntelは RdRand CPU命令を追加し、AMDは2015年6月にそれを追加しました。 (インライン)アセンブリ、乱数を生成する最速の方法は、RdRand CPU命令を呼び出して here のように16ビット、32ビット、または64ビットの乱数を取得することです。コード例については、ページのほぼ中央までスクロールします。そのリンクには、RdRand命令のサポートについて現在のCPUをチェックするためのコード例もあります。CPUID命令でこれを行う方法の説明については、Wikipediaも参照してください。

関連する質問: Sandy Bridgeのハードウェアの真の乱数ジェネレーターを使用しますか? (Wikipediaによると、RdRand命令はIvy Bridgeに初めて登場しましたが、その質問にあるSandy Bridgeアーキテクチャではありません)

_ rdrand64_step() に基づくC++コードの例:

#include <immintrin.h>

uint64_t randVal;
if(!_rdrand64_step(&randVal)) {
  // Report an error here: random number generation has failed!
}
// If no error occured, randVal contains a random 64-bit number
6
Serge Rogatch

この投稿でも何年も経ちますが、似たような答えを探していたときに現れました。そこで、見つけたものを追加します。

_#include <random>_ msdnエントリ

このアプローチは、自己完結型のランダムジェネレーターを構築しますが、Rand()%x;よりもはるかにランダムであることがわかりました。数十万回以上の反復。 Rand()%は、1回おきに65k回試行する必要がある場合に、16個以上の頭/尾を連続してスローしません。これはそれを行うだけでなく、四分の一の時間でそれを行います。

これは私が_#include <random>_を自分で実装する方法です:

_//create rng_gen, using mt technique, with range 0,1 (coin) and 1,6(dice);
std::random_device rd; //seed
std::mt19937 gen(rd()); //seed for rd(Mersenne twister)
std::uniform_int_distribution<> rng_coin(0, 1); //rng1 range
std::uniform_int_distribution<> rng_dice(1, 6); ///rng2 range

rng_coin(gen); //will apply rng1 range on (gen) object. Is very fast
rng_dice(gen); //will apply rng2 range, returns int.

//will output 1000 cointosses to console
for (int i=0;i<1000;++i)std::cout<<rng_coin(gen)<<"\n";
//will generate 1000 dice throws
for (int i=0;i<1000;++i)rng_dice(gen);
_
2
Charlie

Boostライブラリには、ランダムジェネレーターのセットがあります。パフォーマンスチャートが見つかりました こちら

編集:この回答は、元の質問の編集の前にここにありました。しかし、それがまだ役立つといいので、ここに置いておきます。

Rand()は本当に速いので、もっと早く見つかるとは思わない。

それが実際にあなたを遅くしている場合(私はちょっと疑っています)、あなたはアーキテクチャの変更が必要です。

乱数を含む長いリストを事前に設定することをお勧めしますバックグラウンドスレッドでリストを再入力できる場合があります。

1
abelenky

事前にランダムなビットの束を事前に生成し、一度に2つはがすことができます(1から3の間の乱数のみが必要なため)。

0
Mikeb

WELLはかなり良いと思うし、WELL512aはかなり短いと思う。 http://www.iro.umontreal.ca/~panneton/WELLRNG.html WELL44497aも当時は複雑です。ただし、WELLは0〜1の数値を生成します。

0
user2700021