私はC++でゲームを作成していますが、タイルにランダムなブール値(yesまたはno)を入力する必要があります。これは、yesかnoかによって決定されrand() % 1
ます。あまりランダムではありません。
srand
起動時にwithを使用しctime
ていますが、同じパターンが出てきているようです。
非常に乱数を生成するアルゴリズムはありますか?または私がどのように改善できるかについての提案はありますrand()
か?
真のランダム性は、あまりランダムに見えないことがよくあります。奇妙な実行が見られることを期待してください。
しかし、あなたが助けるためにあなたがすることができる少なくとも1つの即時のことは、最下位ビットだけを使用することを避けることです。Cで数値レシピを引用するには:
1から10までのランダムな整数を生成する場合は、次のように、常に上位ビットを使用して生成する必要があります。
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
それに似たものは決してありません
j = 1 + (rand() % 10);
(下位ビットを使用します)。
また、代わりに、より優れたプロパティを持つ別のRNGの使用を検討することもできます。Xorshiftアルゴリズムは優れた代替手段です。ほんの数行のCでスピーディーでコンパクトであり、ほぼすべてのゲームで統計的に十分に優れているはずです。
下位ビットはあまりランダムではありません。
%2を使用すると、乱数の最下位ビットのみをチェックします。
暗号強度のランダム性は必要ないと仮定します。
そうすれば、次のことがOKになるはずです。
bool tile = rand() > (RAND_MAX / 2);
別のPRNGを記述したり、ライブラリを使用したりする以外にできる最も簡単な方法は、1回の呼び出しで得られるすべてのビットを使用するrand()
ことです。ほとんどの乱数ジェネレーターは、特定のランダム性と統計的特性を持つビットのストリームに分解できます。そのストリーム上で等間隔に配置された個々のビットは、同じプロパティを持つ必要はありません。基本的に、ここでは14〜31ビットの疑似ランダム性を捨てています。
の呼び出しによって生成された数値をキャッシュして、そのrand()
各ビットを使用することができrand()
ます(もちろん、ビット数に応じて、に依存しますRAND_MAX
)。したがって、RAND_MAX
32768の場合は、その番号の最下位15ビットを順番に使用できます。特にRAND_MAX
、ジェネレータの下位ビットを処理していない場合は、ハイエンドからビットを取得してもあまりメリットはありません。たとえば、Microsoft CRTは、次の方程式を使用して乱数を生成します。
x n + 1 = x n・214013 + 2531011
次に、その結果の最下位16ビットをシフトアウトし、15ビットに制限します。したがって、ジェネレータからの下位ビットはありません。RAND_MAX
これは、2 31の高さのジェネレーターにもほぼ当てはまりますが、それを当てにすることができない場合もあります(したがって、上位側から取得した16ビットまたは24ビットに制限することもできます)。
したがって、通常は、への呼び出しの結果をキャッシュしrand()
、アプリケーションでは、の代わりにその番号のビットを順番に使用しますrand() % 2
。
多くの疑似乱数ジェネレータは、周期的な下位ビット、特に線形合同アルゴリズムに悩まされています。これは通常、最も一般的な実装です。これを解決するために最下位ビットをシフトアウトすることを提案する人もいます。
私は長年、メルセンヌツイスター乱数ジェネレーターをうまく使用してきました。そのソースコードは、広島経済大学の数学科から入手できます。(日本語を読まなくてもいいので直接リンク!)
このアルゴリズムの優れている点は次のとおりです。
あなたのゲームを見てみることをお勧めします。
C ++ 11には、メルセンヌティッティツイスターアルゴリズムを実装する次の方法があります。cppreference.comから:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
これにより、他の多くの乱数ジェネレーターの欠点なしに、シミュレーションに適した乱数が生成されます。暗号化には適していません。ただし、暗号化乱数ジェネレーターは計算量が多くなります。
十分に等分配された長周期線形アルゴリズムもあります。多くの実装例があります。
ランダムに「はい」または「いいえ」の完璧な方法は、それらを切り替えることです。ランダム関数は必要ないかもしれません。
標準の乱数ジェネレータの最下位ビットはそれほどランダムではありません。これはよく知られている問題です。
ブースト乱数ライブラリを調べます。
数値がもう少しランダムに感じられるかもしれない簡単なことは、条件if(rand() % 50==0)
が真になるたびにジェネレーターを再シードすることです。
下位ビットはランダムではないと言われています。だから真ん中から何かを試してみてください。これにより、28番目のビットが取得されます。
(rand() >> 13) % 2
クヌースは、減法混色法による乱数生成を提案しています。それはかなりランダムであると信じられています。スキーム言語でのサンプル実装については、こちらを参照してください
良い結果を得るには乱数を使用する場合、実際には、複数のジェネレーターの結果を組み合わせたジェネレーターが必要です。一番下のビットを破棄するだけでは、かなりばかげた答えです。
キャリー付き乗算は実装が簡単で、それ自体で良い結果が得られます。それらをいくつか持っていて、結果を組み合わせると、非常に良い結果が得られます。また、多くのメモリを必要とせず、非常に高速です。
また、再シードが速すぎると、まったく同じ数になります。個人的には、時間が変わったときにだけシードを更新するクラスを使用しています。