質問
いて教えてほしい"良い"方法を初期化する擬似乱数ジェネレータはC++.がその場で発音を確認することが 記事 この状態:
を生成させるためには、ランダムなど 数srandは、通常の初期化 一部の特徴的な価値により、 関連するの実行ます。のための の値によって返される 機能時に宣言されたヘッダー ctime)はそれぞれ異なる第二に、 がでほとんど randomingます。
Unixtimeな独特のが私の願います。何より良い方法を初期化する方法について。ボーナスポイントな携帯用のものコードは、主にLinuxで動作する。
私は考えているpid/unixtime数をint、またはその疑いのあるデータを読み込むから /dev/urandom
.
よろしく!
編集
あり、実際に開始申込み複数回、私は運が衝突した際に
解決
最良の答えは、Boost乱数を使用することです。または、C ++ 11にアクセスできる場合は、 <random>
ヘッダーを使用します。
しかし、rand()
およびsrand()
について話している場合
最良の方法は、単にtime()
:
int main()
{
srand(time(NULL));
...
}
<=>!
を呼び出すたびにではなく、プログラムの最初にこれを行うようにしてください。起動するたびに、time()は一意の値を返します(アプリケーションを1秒間に複数回起動しない限り)。 32ビットシステムでは、60年ごとにしか繰り返されません。
時間は十分にユニークだとは思わないが、信じがたいと思う。しかし、私は間違っていることが知られています。
アプリケーションの多くのコピーを同時に開始する場合、より細かい解像度のタイマーを使用できます。ただし、値が繰り返されるまでの期間が短くなるリスクがあります。
OK。そのため、1秒間に複数のアプリケーションを起動していると思われる場合。
次に、タイマーの粒度を細かくします。
int main()
{
struct timeval time;
gettimeofday(&time,NULL);
// microsecond has 1 000 000
// Assuming you did not need quite that accuracy
// Also do not assume the system clock has that accuracy.
srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
// The trouble here is that the seed will repeat every
// 24 days or so.
// If you use 100 (rather than 1000) the seed repeats every 248 days.
// Do not make the MISTAKE of using just the tv_usec
// This will mean your seed repeats every second.
}
他のヒント
これは、頻繁に(1秒間に複数回)実行できる小さなコマンドラインプログラムに使用したものです。
unsigned long seed = mix(clock(), time(NULL), getpid());
ミックスの場所:
// http://www.concentric.net/~Ttwang/tech/inthash.htm
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
a=a-b; a=a-c; a=a^(c >> 13);
b=b-c; b=b-a; b=b^(a << 8);
c=c-a; c=c-b; c=c^(b >> 13);
a=a-b; a=a-c; a=a^(c >> 12);
b=b-c; b=b-a; b=b^(a << 16);
c=c-a; c=c-b; c=c^(b >> 5);
a=a-b; a=a-c; a=a^(c >> 3);
b=b-c; b=b-a; b=b^(a << 10);
c=c-a; c=c-b; c=c^(b >> 15);
return c;
}
より良い乱数ジェネレーターが必要な場合は、libc randを使用しないでください。代わりに、/dev/random
や/dev/urandom
のようなものを直接使用します(int
から直接読み取るか、そのようなものを使用します)。
libc randの唯一の本当の利点は、シードが与えられると、予測可能であり、デバッグに役立つことです。
Windowsの場合:
srand(GetTickCount());
ミリ秒単位であるため、time()
よりも優れたシードを提供します。
C++11 random_device
が必要な場合なお、それを用いてはいけませんrand()を初めをお使いください <random>
図書館があります。でつくキックでゴールネット機能など様々な用エンジンの異なる品質/サイズ/業績トレードオフ、再entrancy、事前に定義された分布だけで終わって間違っています。でもご利用いただけます。非決定的なランダムなデータ(例えば、/dev/ランダム)によって実装されます。
#include <random>
#include <iostream>
int main() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist{1,100};
for (int i=0; i<50; ++i)
std::cout << dist(eng) << '\n';
}
eng
する乱数の発生源、内蔵の実施メルセンヌツイスター.また種子を用いてrandom_device、何も実装することによりdetermanistic RNG、seed_seq合以上の32ビットのランダムなデータです。例えば、libc++random_deviceアクセス/dev/urandomによるデフォルトができるで別ファイルにアクセスします。
次を作成して配布などを踏まえると、乱数の発生源、呼び出しを繰り返しの分布を一様分布のint値を1から100です。その進行を繰り返し印刷します。
最良の方法は、別の擬似乱数ジェネレータを使用することです。 メルセンヌツイスター(およびWichmann-Hill)は私の推奨です。
iは、mozillaコードでunix_random.cファイルを見ることを提案します。 (mozilla / security / freebl /であると推測します...)freeblライブラリにあるはずです。
システムコール情報(pwd、netstatなど)を使用して乱数のノイズを生成します。これは、ほとんどのプラットフォームをサポートするように記述されています(ボーナスポイントを獲得できます:D)。
あなたが自問しなければならない本当の質問は、あなたが必要とするランダム性の質です。
libc randomは LCG
です。ランダムの品質は、srandを提供する入力が何であれ低くなります。
異なるインスタンスが異なる初期化を確実に行う必要がある場合、プロセスID(getpid)、スレッドID、タイマーを混在させることができます。結果をxorと混合します。ほとんどのアプリケーションではエントロピーで十分です。
例:
struct timeb tp;
ftime(&tp);
srand(static_cast<unsigned int>(getpid()) ^
static_cast<unsigned int>(pthread_self()) ^
static_cast<unsigned int >(tp.millitm));
ランダム品質を向上させるには、/ dev / urandomを使用します。 boost :: threadおよびboost :: date_timeを使用して、上記のコードを移植可能にすることができます。
ジョナサン・ライトによる上位投票投稿のc++11
バージョン:
#include <ctime>
#include <random>
#include <thread>
...
const auto time_seed = static_cast<size_t>(std::time(0));
const auto clock_seed = static_cast<size_t>(std::clock());
const size_t pid_seed =
std::hash<std::thread::id>()(std::this_thread::get_id());
std::seed_seq seed_value { time_seed, clock_seed, pid_seed };
...
// E.g seeding an engine with the above seed.
std::mt19937 gen;
gen.seed(seed_value);
#include <stdio.h>
#include <sys/time.h>
main()
{
struct timeval tv;
gettimeofday(&tv,NULL);
printf("%d\n", tv.tv_usec);
return 0;
}
tv.tv_usecはマイクロ秒単位です。これは受け入れ可能なシードでなければなりません。
次のようなシグネチャを持つ関数があるとします:
int foo(char *p);
ランダムシードのエントロピーの優れたソースは、次のハッシュです:
- 下位ビットを捨てずに
clock_gettime
(秒およびナノ秒)の完全な結果-それらは最も価値があります。 -
p
の値、uintptr_t
にキャスト。 -
rand
のアドレス、srand
にキャスト。
少なくとも3番目、場合によっては2番目でも、システムのASLRからエントロピーを取得します(利用可能な場合、初期スタックアドレス、つまり現在のスタックアドレスは多少ランダムです)。
また、グローバル状態に触れないために、<=> / <=>を完全に使用することも避けます。したがって、使用するPRNGをより詳細に制御できます。ただし、上記の手順は、使用するPRNGに関係なく、多くの作業をせずに適切なエントロピーを取得するのに適した(かなり移植性の高い)方法です。
Visual Studioを使用している場合は、さらに別の方法があります:
#include "stdafx.h"
#include <time.h>
#include <windows.h>
const __int64 DELTA_EPOCH_IN_MICROSECS= 11644473600000000;
struct timezone2
{
__int32 tz_minuteswest; /* minutes W of Greenwich */
bool tz_dsttime; /* type of dst correction */
};
struct timeval2 {
__int32 tv_sec; /* seconds */
__int32 tv_usec; /* microseconds */
};
int gettimeofday(struct timeval2 *tv/*in*/, struct timezone2 *tz/*in*/)
{
FILETIME ft;
__int64 tmpres = 0;
TIME_ZONE_INFORMATION tz_winapi;
int rez = 0;
ZeroMemory(&ft, sizeof(ft));
ZeroMemory(&tz_winapi, sizeof(tz_winapi));
GetSystemTimeAsFileTime(&ft);
tmpres = ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
/*converting file time to unix epoch*/
tmpres /= 10; /*convert into microseconds*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
tv->tv_sec = (__int32)(tmpres * 0.000001);
tv->tv_usec = (tmpres % 1000000);
//_tzset(),don't work properly, so we use GetTimeZoneInformation
rez = GetTimeZoneInformation(&tz_winapi);
tz->tz_dsttime = (rez == 2) ? true : false;
tz->tz_minuteswest = tz_winapi.Bias + ((rez == 2) ? tz_winapi.DaylightBias : 0);
return 0;
}
int main(int argc, char** argv) {
struct timeval2 tv;
struct timezone2 tz;
ZeroMemory(&tv, sizeof(tv));
ZeroMemory(&tz, sizeof(tz));
gettimeofday(&tv, &tz);
unsigned long seed = tv.tv_sec ^ (tv.tv_usec << 12);
srand(seed);
}
少しやり過ぎかもしれませんが、短い間隔でうまく機能します。 gettimeofday関数がこちら。
編集:さらなる調査の結果、rand_sはVisual Studioの優れた代替手段になる可能性があります。これは単なるrand()ではなく、まったく異なるものであり、srandのシードを使用しません。私はそれがちょうど<!> quot; safer <!> quot; randとほぼ同一であると推測していました。
rand_sを使用するには、stdlib.hがインクルードされる前に_CRT_RAND_Sを#defineすることを忘れないでください。
プログラムがLinuxでのみ実行されている限り(およびプログラムがELF実行可能ファイルである限り)、カーネルがプロセスにELF auxベクトルの一意のランダムシードを提供することが保証されます。カーネルは、プロセスごとに異なる16のランダムバイトを提供します。これはgetauxval(AT_RANDOM)
で取得できます。これらをsrand
に使用するには、そのようなint
のみを使用します。
#include <sys/auxv.h>
void initrand(void)
{
unsigned int *seed;
seed = (unsigned int *)getauxval(AT_RANDOM);
srand(*seed);
}
これは他のELFベースのシステムにも変換される可能性があります。 Linux以外のシステムにどのaux値が実装されているかわかりません。
プログラムの上部にヘッダーを含め、次のように記述します。
srand(time(NULL));
乱数を宣言する前のプログラムで。 1〜10の乱数を出力するプログラムの例を次に示します。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
//Initialize srand
srand(time(NULL));
//Create random number
int n = rand() % 10 + 1;
//Print the number
cout << n << endl; //End the line
//The main function is an int, so it must return a value
return 0;
}