longで指定範囲の乱数

ポウラナー ヘフェ ヴァイスビア

結局、乱数が一様であれば、それを分割した部分も一様になるはずなので、基本的にはgetLong() % nで大丈夫そうです。ただ、そうするとlongの範囲が割り切れなかった部分で、乱数にムラができるので、考慮する必要があります。
で、結局そうすると、nがintの範囲ならgetInt(n)を使って、intの範囲を超えていればgetLongでn以上のものを捨てれば大丈夫じゃないかということになりました。
なので、結局こんな感じになります。

public long nextLong(Random r, long n){
    if(n <= Integer.MAX_VALUE) return r.nextInt((int)n);
    for(;;){
        long t = r.nextLong();
        if(t < 0) t -= Long.MIN_VALUE;
        if(t < n) return t;
    }
}


ということをquintiaさんから教えてもらいました。java.util.Randomですべてのlongが生成できないという問題は、メルセンヌ・ツイスターで解決。
http://materia.jp/blog/20081110.html#p02


追記。なんか勘違いがありました。結局、nextInt(int)と同じことをやればよいだけでした。

long nextLong(long n){
  long bits, value;
  do{
    bits = r.nextLong();
    if(bits < 0) bits -= Long.MIN_VALUE;
    val = bits % n;
  } while (bits - val + (n - 1);
  return val;
}

フェルマーテストで素数判定

longの乱数が欲しかったのは、素数判定がやりたかったからなのですが、確認のためにエラトステネスの篩との比較をしたので、結局intの範囲までしか使いませんでした。
素数判定には、フェルマーテストを使います。で、今回は、わざと判定回数を少なくしてみて誤判定させています。
そうすると、こんな感じの実行結果になりました。

1729が素数と誤判定
8911が素数と誤判定
29341が素数と誤判定
46657が素数と誤判定
52633が素数と誤判定
75361が素数と誤判定


なんどか実行すると、誤判定が起きる数はいくつかに決まっていることがわかります。
この数は、カーマイケル数といいます。計算上で素数のようなふるまいをするので、擬素数ともいいます。


ソースはこんな感じ。

続きを読む