How to generate a random BigInteger value in Java?
我需要生成0(包含)到n(包含)范围内任意大的随机整数。我最初的想法是调用
1 |
Constructs a randomly generated BigInteger, uniformly distributed over the range 0 to (2numBits - 1), inclusive.
号
怎样才能得到0-n范围内的随机值,其中n不是2的幂?
使用循环:
1 2 3 4 | BigInteger randomNumber; do { randomNumber = new BigInteger(upperLimit.bitLength(), randomSource); } while (randomNumber.compareTo(upperLimit) >= 0); |
平均而言,这将需要少于两次迭代,并且选择将是一致的。
编辑:如果您的RNG很昂贵,您可以通过以下方式限制迭代次数:
1 2 3 4 5 6 7 8 | int nlen = upperLimit.bitLength(); BigInteger nm1 = upperLimit.subtract(BigInteger.ONE); BigInteger randomNumber, temp; do { temp = new BigInteger(nlen + 100, randomSource); randomNumber = temp.mod(upperLimit); } while (s.subtract(randomNumber).add(nm1).bitLength() >= nlen + 100); // result is in 'randomNumber' |
号
在这个版本中,循环被多次占用是非常不可能的(在2^100中不到一次机会,也就是说,远小于主机在接下来的一秒钟内自动着火的概率)。另一方面,
下面的方法使用
1 2 3 4 5 6 7 8 | public BigInteger nextRandomBigInteger(BigInteger n) { Random rand = new Random(); BigInteger result = new BigInteger(n.bitLength(), rand); while( result.compareTo(n) >= 0 ) { result = new BigInteger(n.bitLength(), rand); } return result; } |
这样做的缺点是,构造函数被调用的次数未指定,但在最坏的情况下(n只是略大于2的幂),对构造函数的预期调用次数应该只有2次左右。
最简单的方法(相当长的一段时间)是使用指定的构造函数生成一个具有正确位数的随机数(
只需使用模块化缩减
1 |
。
以下是我如何在一个名为generic_biginteger的类中执行此操作,该类可通过以下方式获得:安迪·特纳的通用源代码网页
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | /** * There are methods to get large random numbers. Indeed, there is a * constructor for BigDecimal that allows for this, but only for uniform * distributions over a binary power range. * @param a_Random * @param upperLimit * @return a random integer as a BigInteger between 0 and upperLimit * inclusive */ public static BigInteger getRandom( Generic_Number a_Generic_Number, BigInteger upperLimit) { // Special cases if (upperLimit.compareTo(BigInteger.ZERO) == 0) { return BigInteger.ZERO; } String upperLimit_String = upperLimit.toString(); int upperLimitStringLength = upperLimit_String.length(); Random[] random = a_Generic_Number.get_RandomArrayMinLength( upperLimitStringLength); if (upperLimit.compareTo(BigInteger.ONE) == 0) { if (random[0].nextBoolean()) { return BigInteger.ONE; } else { return BigInteger.ZERO; } } int startIndex = 0; int endIndex = 1; String result_String =""; int digit; int upperLimitDigit; int i; // Take care not to assign any digit that will result in a number larger // upperLimit for (i = 0; i < upperLimitStringLength; i ++){ upperLimitDigit = new Integer( upperLimit_String.substring(startIndex,endIndex)); startIndex ++; endIndex ++; digit = random[i].nextInt(upperLimitDigit + 1); if (digit != upperLimitDigit){ break; } result_String += digit; } // Once something smaller than upperLimit guaranteed, assign any digit // between zero and nine inclusive for (i = i + 1; i < upperLimitStringLength; i ++) { digit = random[i].nextInt(10); result_String += digit; } // Tidy values starting with zero(s) while (result_String.startsWith("0")) { if (result_String.length() > 1) { result_String = result_String.substring(1); } else { break; } } BigInteger result = new BigInteger(result_String); return result; } |
为什么不先构造一个随机的biginteger,然后从中构造一个bigdecimal呢?在bigdecimal中有一个构造函数:
将这个F代码编译成一个dll,您也可以在C/vb.net程序中引用它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | type BigIntegerRandom() = static let internalRandom = new Random() /// Returns a BigInteger random number of the specified number of bytes. static member RandomBigInteger(numBytes:int, rand:Random) = let r = if rand=null then internalRandom else rand let bytes : byte[] = Array.zeroCreate (numBytes+1) r.NextBytes(bytes) bytes.[numBytes] <- 0uy bigint bytes /// Returns a BigInteger random number from 0 (inclusive) to max (exclusive). static member RandomBigInteger(max:bigint, rand:Random) = let rec getNumBytesInRange num bytes = if max < num then bytes else getNumBytesInRange (num * 256I) bytes+1 let bytesNeeded = getNumBytesInRange 256I 1 BigIntegerRandom.RandomBigInteger(bytesNeeded, rand) % max /// Returns a BigInteger random number from min (inclusive) to max (exclusive). static member RandomBigInteger(min:bigint, max:bigint, rand:Random) = BigIntegerRandom.RandomBigInteger(max - min, rand) + min |
。