web-dev-qa-db-ja.com

Rand()関数なしで乱数を生成するにはどうすればよいですか?

0とある整数の間の(擬似)乱数を生成したい。それらがランダムすぎないかどうかは気にしません。現在の時刻にはアクセスできますが、ランド関数にはアクセスできません。誰もがこれらを生成する十分に堅牢な方法を考えることができますか?おそらく、時刻からいくつかのビットを破棄し、整数または何かを法としていますか?

私はcを使用しています。

23
AnkurVj

超シンプルな擬似ランダムジェネレーターを使用している場合は、 Linear Feedback shift Register を使用できます。

ウィキペディアの記事にはいくつかのコードスニペットがありますが、基本的に16ビットジェネレーターのコードは次のようになります(そのページから軽くマッサージされています...)

  unsigned short lfsr = 0xACE1u;
  unsigned bit;

  unsigned Rand()
  {
    bit  = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
    return lfsr =  (lfsr >> 1) | (bit << 15);
  }
29
Roddy

「ランダムすぎない」整数の場合、現在のUNIX時間から始めて、再帰式r = ((r * 7621) + 1) % 32768;を使用できます。 0(包括的)とM(包括的)の間のn番目のランダムな整数は、n回目の反復の後、r % Mになります。

これは線形合同ジェネレータと呼ばれます。

再帰式は、クイックソート実装でピボットを選択するためにbzip2が使用するものです。私は他の目的については知りませんが、この特定の目的にはかなりうまくいきます...

11
Dennis

独自の疑似乱数ジェネレーター(「内部」Rand())の実装を見てください。たとえば、 Mersenne twister は高く評価されています。

7
unwind

rangesで動作する最小でシンプルなランダムジェネレーターを、完全に機能する例を以下に示します。

unsigned int MyRand(unsigned int start_range,unsigned int end_range)
  {
    static unsigned int Rand = 0xACE1U; /* Any nonzero start state will work. */

    /*check for valid range.*/
    if(start_range == end_range) {
        return start_range;
    }

    /*get the random in end-range.*/
    Rand += 0x3AD;
    Rand %= end_range;

    /*get the random in start-range.*/
    while(Rand < start_range){
        Rand = Rand + end_range - start_range;
    }

    return Rand;
  }

int main(void)
{
    int i;
    for (i = 0; i < 0xFF; i++)
    {
    printf("%u\t",MyRand(10,20));
    }
    return 0;
}
0
HaSeeB MiR

これを行う唯一の「堅牢な」(簡単に予測できない)方法は、独自の擬似乱数ジェネレータを作成し、現在の時刻をシードすることです。必須のウィキペディアリンク: http://en.wikipedia.org/wiki/Pseudorandom_number_generator

0
Staven

「Tiny Mersenne Twister」はこちらから入手できます。 http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html

純粋なcであり、使用方法は簡単です。例えば。時間を使うだけです:

#include "tinymt32.h"
// And if you can't link:
#include "tinymt32.c"

#include <time.h>
#include <stdio.h>

int main(int argc, const char* argv[])
{
    tinymt32_t state;
    uint32_t seed = time(0);

    tinymt32_init(&state, seed);

    for (int i=0; i<10; i++)
            printf("random number %d: %u\n", i, (unsigned int)tinymt32_generate_uint32(&state));
}
0
Dominic

数値をあまり速く生成せず(* 1)、上限が十分に低く(* 2)、「時刻」にナノ秒が含まれている場合は、それらのナノ秒を使用します。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int nanorand(void) {
    struct timespec p[1];
    clock_gettime(CLOCK_MONOTONIC, p);
    return p->tv_nsec % 1000;
}

int main(void) {
    int r, x;
    for (;;) {
        r = nanorand();
        do {
            printf("please type %d (< 50 quits): ", r);
            fflush(stdout);
            if (scanf("%d", &x) != 1) exit(EXIT_FAILURE);
        } while (x != r);
        if (r < 50) break;
    }
    puts("");
    return 0;
}

そして、サンプルの実行...

タイプ769(<50 quits):769 
 please type 185(<50 quits):185 
 please type 44(<50 quits):44 

(* 1)一度に1つずつインタラクティブに使用している場合
(* 2)約1000までの数字が必要な場合

0
pmg