对于那些仍在问这个问题并正在寻找一种在正整数范围内生成任意大随机BigInteger的方法的人,这就是我想出的。此随机生成器无需尝试一堆数字即可工作,直到其中一个适合该范围。相反,它将直接生成一个适合给定范围的随机数。
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。
然后它创建BigDecimals来表示最大可能值(在前面的示例中为 9999)和最小值 (0),并将范围参数BigIntegers转换为BigDecimals。同样在此步骤中,给定范围的最大值加 1,以便在下一步中纠正舍入误差。
然后使用此公式将生成的随机数映射到给定范围:
(generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
之后,它将最后检查映射的数字是否适合给定范围,如果不适合,则将其设置为给定范围最大值。这样做是为了纠正舍入误差。