まだこの質問をしていて、正の整数範囲内で任意に大きなランダムなBigIntegersを生成する方法を探している人のために、これが私が思いついたものです。この乱数発生器は、範囲に収まるまで多数の数値を試行せずに機能します。代わりに、指定された範囲に適合する乱数を直接生成します。
private static BigInteger RandomBigInteger(BigInteger rangeStart, BigInteger rangeEnd){
Random rand = new Random();
int scale = rangeEnd.toString().length();
String generated = "";
for(int i = 0; i < rangeEnd.toString().length(); i++){
generated += rand.nextInt(10);
}
BigDecimal inputRangeStart = new BigDecimal("0").setScale(scale, RoundingMode.FLOOR);
BigDecimal inputRangeEnd = new BigDecimal(String.format("%0" + (rangeEnd.toString().length()) + "d", 0).replace('0', '9')).setScale(scale, RoundingMode.FLOOR);
BigDecimal outputRangeStart = new BigDecimal(rangeStart).setScale(scale, RoundingMode.FLOOR);
BigDecimal outputRangeEnd = new BigDecimal(rangeEnd).add(new BigDecimal("1")).setScale(scale, RoundingMode.FLOOR); //Adds one to the output range to correct rounding
//Calculates: (generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
BigDecimal bd1 = new BigDecimal(new BigInteger(generated)).setScale(scale, RoundingMode.FLOOR).subtract(inputRangeStart);
BigDecimal bd2 = inputRangeEnd.subtract(inputRangeStart);
BigDecimal bd3 = bd1.divide(bd2, RoundingMode.FLOOR);
BigDecimal bd4 = outputRangeEnd.subtract(outputRangeStart);
BigDecimal bd5 = bd3.multiply(bd4);
BigDecimal bd6 = bd5.add(outputRangeStart);
BigInteger returnInteger = bd6.setScale(0, RoundingMode.FLOOR).toBigInteger();
returnInteger = (returnInteger.compareTo(rangeEnd) > 0 ? rangeEnd : returnInteger); //Converts number to the end of output range if it's over it. This is to correct rounding.
return returnInteger;
}
それはどのように機能しますか?
最初に、最大範囲と同じ長さの乱数で文字列を生成します。例: 10 ~ 1000 の範囲を指定すると、0000 ~ 9999 の間の数値がStringとして生成されます。
次に、可能な最大値 (前の例では 9999) と最小値 (0) を表すBigDecimalsを作成し、範囲パラメーターBigIntegersをBigDecimalsに変換します。また、このステップでは、次のステップで丸め誤差を修正するために、指定された範囲の最大値に 1 が追加されます。
次に、この式を使用して、生成された乱数が指定された範囲にマップされます。
(generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
その後、マップされた数値が指定された範囲に適合するかどうかの最後のチェックを行い、適合しない場合は指定された範囲の最大値に設定します。これは、丸め誤差を修正するために行われます。