ちょっと学んだので整理。
まずJavaにはランダムを提供するクラスとして
の2つがあってRandomクラスは以下のような強度しか持っていない。
Random クラスのインスタンスは、一連の擬似乱数を生成します。クラスでは 48 ビットのシードを使い、このシードは線形合同法で変更されます。
http://sdc.sun.co.jp/java/docs/j2se/1.4/ja/docs/ja/api/java/util/Random.html
しかも初期化があまりよくなくて初回の乱数がとても偏る。
Random r = new java.util.Random(); double x, min = 1, max = 0; for (int i = 0; i < 1024; i++) { r.setSeed(i); x = r.nextDouble(); if (x > max) max = x; if (x < min) min = x; } System.out.println("Min=" + min + " Max=" + max);
Min=0.6753377750582709 Max=0.7669794809891215
こんなプログラムを回してみるとと1000通りの種を渡しても初回生成値が極度に偏ってしまう。
んで、SecureRandomはこのあたりの問題を解消するのでててきた。
for (int i = 0; i < 1024; i++) { sr.setSeed(i); x = sr.nextDouble(); if (x > max){ max = x; } if (x < min){ min = x; } } BigDecimal bigMin = new BigDecimal(min).setScale(16,BigDecimal.ROUND_HALF_UP); System.out.println("Min=" + bigMin + " Max=" + max); x = 0.0;
Min=0.0004351500205996 Max=0.9986417236968099
SecureRandomにすると一気に分散するようになった。
ランダムな文字列を生成するには
そもそもランダムな文字列を作る為にRandomを久々にみてたわけですが、
今普通にランダムな文字列を使うのならcommons-langのRandomStringUtilsで事足りる。
アスキー文字なら
RandomStringUtils.randomAscii(10) ⇒DF|M1!7W=@
アルファベットなら
RandomStringUtils.randomAlphabetic(10) ⇒doKntQIMve
数字なら(0始まりも生成されてしまうので注意)
RandomStringUtils.randomNumeric(10) ⇒8266471697 頭0を嫌うなら RandomStringUtils.random(1,"123456789") + RandomStringUtils.randomNumeric(9);
自分で指定した文字の中からランダムにしたいのなら
RandomStringUtils.random(10,"012345abcdef"); ⇒c021cc0b24
長さもランダムにしたいのならRandomUtils.nextIntと組み合わせて(1〜3文字のランダムな文字が変える)
RandomStringUtils.random(RandomUtils.nextInt(3)+1,"12345678"); ⇒1 ⇒255 ⇒86
まあつまりコモンズはすごいよねっていうエントリーです><
良い乱数・悪い乱数
commons-langでランダムな値を生成する--commons-langの便利メソッド - builder by ZDNet Japan