如何在Java中创建随机BigDecimal?

这个问题: 如何生成随机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,1]中的均匀分布数和精度N十进制数​​,生成小于10 * N的统一BigInteger, 并将其缩小10 * N.

我发了一篇关于生成随机BigInteger Andy Turner关于生成随机BigInteger的答案的post。 我不直接使用它来生成随机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; } 

我可能会错过这里显而易见的但是如何创建两个随机的BigInteger ,一个是整数部分,另一个是小数? 显然,“分数”bigint的范围将由您想要允许的精度决定,而您无法远离固定。

更新:这可以进一步简化,只使用一个随机bigint。 如果你想要一个介于0和n之间的随机数,其中k为十进制精度(其中k是常数),你只需生成一个0到n * 10 ^ k之间的随机数,然后除以10 ^ k。