这个问题:How to generate a random BigInteger描述了一种实现与BigIntegers的Random.nextInt(int n)相同语义的方法。
我想对BigDecimal和Random.nextDouble()做同样的事情。
上述问题中的一个答案建议创建一个随机的BigInteger,然后使用随机比例从中创建一个BigDouble。一个非常快速的实验表明这是一个非常糟糕的主意:)
我的直觉是使用这种方法需要通过像n-log10(R)
这样的整数来缩放整数,其中n是输出中所需精度的位数,R是随机BigInteger。这应该允许存在正确的位数,以便(例如)1 - > 10 ^ -64和10 ^ 64 - > 1。击>
还需要正确选择缩放值,使结果落在[0,1]范围内。
之前是否有人这样做过,他们是否知道结果是否正确分发?有没有更好的方法来实现这一目标?
编辑:感谢@biziclop纠正了我对scale参数的理解。以上不是必需的,恒定的比例因子具有预期的效果。
供以后参考,我(显然是工作代码)是:
private static BigDecimal newRandomBigDecimal(Random r, int precision) {
BigInteger n = BigInteger.TEN.pow(precision);
return new BigDecimal(newRandomBigInteger(n, r), precision);
}
private static BigInteger newRandomBigInteger(BigInteger n, Random rnd) {
BigInteger r;
do {
r = new BigInteger(n.bitLength(), rnd);
} while (r.compareTo(n) >= 0);
return r;
}
答案 0 :(得分:3)
这肯定很容易......如果我只知道你想要什么。对于范围[0,1]中的均匀分布数和精度N十进制数,生成小于10 * N的统一BigInteger,并将其缩小10 * N.
答案 1 :(得分:2)
我发了一篇关于生成随机BigInteger Andy Turner's answer about generating a random BigInteger的帖子。我不直接使用它来生成随机BigDecimal。基本上我关心的是使用Random的独立实例来生成数字中的每个数字。我注意到的一个问题是,对于Random,只有很多值和特定数字连续排在一起。此外,该代试图保持生成值的均匀分布。我的解决方案取决于存储一个数组或一组Random实例并调用它们的东西。我认为这是一个很好的方式来实现它,我想找出来,所以如果有人对这种方法有任何指示或批评,我感兴趣。
/**
*
* @param a_Random
* @param decimalPlaces
* @param lowerLimit
* @param upperLimit
* @return a pseudo randomly constructed BigDecimal in the range from
* lowerLimit to upperLimit inclusive and that has up to decimalPlaces
* number of decimal places
*/
public static BigDecimal getRandom(
Generic_Number a_Generic_Number,
int decimalPlaces,
BigDecimal lowerLimit,
BigDecimal upperLimit) {
BigDecimal result;
BigDecimal range = upperLimit.subtract(lowerLimit);
BigDecimal[] rangeDivideAndRemainder =
range.divideAndRemainder(BigDecimal.ONE);
BigInteger rangeInt = rangeDivideAndRemainder[0].toBigIntegerExact();
BigInteger intComponent_BigInteger = Generic_BigInteger.getRandom(
a_Generic_Number,
rangeInt);
BigDecimal intComponent_BigDecimal =
new BigDecimal(intComponent_BigInteger);
BigDecimal fractionalComponent;
if (intComponent_BigInteger.compareTo(rangeInt) == 0) {
BigInteger rangeRemainder =
rangeDivideAndRemainder[1].toBigIntegerExact();
BigInteger fractionalComponent_BigInteger =
Generic_BigInteger.getRandom(a_Generic_Number, rangeRemainder);
String fractionalComponent_String = "0.";
fractionalComponent_String += fractionalComponent_BigInteger.toString();
fractionalComponent = new BigDecimal(fractionalComponent_String);
} else {
fractionalComponent = getRandom(
a_Generic_Number, decimalPlaces);
}
result = intComponent_BigDecimal.add(fractionalComponent);
result.add(lowerLimit);
return result;
}
/**
* Provided for convenience.
* @param a_Generic_BigDecimal
* @param decimalPlaces
* @return a random BigDecimal between 0 and 1 inclusive which can have up
* to decimalPlaces number of decimal places
*/
public static BigDecimal getRandom(
Generic_Number a_Generic_Number,
int decimalPlaces) {
//Generic_BigDecimal a_Generic_BigDecimal = new Generic_BigDecimal();
Random[] random = a_Generic_Number.get_RandomArrayMinLength(
decimalPlaces);
//System.out.println("Got Random[] size " + random.length);
String value = "0.";
int digit;
int ten_int = 10;
for (int i = 0; i < decimalPlaces; i++) {
digit = random[i].nextInt(ten_int);
value += digit;
}
int length = value.length();
// Tidy values ending with zero's
while (value.endsWith("0")) {
length--;
value = value.substring(0, length);
}
if (value.endsWith(".")) {
value = "0";
}
BigDecimal result = new BigDecimal(value);
//result.stripTrailingZeros();
return result;
}
答案 2 :(得分:1)
我可能会错过这里显而易见的但是如何创建两个随机BigInteger
s,一个是整数部分,另一个是小数?显然,“分数”bigint的范围将取决于你想要允许的精度,这是你无法摆脱固定的。
更新:这可以进一步简化为只使用一个随机bigint。如果你想要一个介于0和n之间的随机数,其中k为十进制精度(其中k是常数),你只需要生成一个介于0和n * 10 ^ k之间的随机数,并将其除以10 ^ k。