使用RandomGenerator(Java 17中引入)创建随机BigInteger

ttisahbt  于 2023-02-11  发布在  Java
关注(0)|答案(1)|浏览(135)

BigInteger类提供构造函数

public BigInteger(int numBits, Random rnd)

从Java 17开始就鼓励使用RandomGenerator。我怎样才能只使用RandomGenerator的一个示例来生成一个随机的BigInteger,取值范围为0...(2^n)-1。

bf1o4zei

bf1o4zei1#

只是使用RandomSecureRandom

为什么需要这个?因为new Random()为您提供了一个相对快速的非安全随机数生成器,而new SecureRandom()提供了一个CSPRNG(加密安全伪随机数生成器)。* 这两个示例都是RandomGenerator接口的示例。* 因此,只有当您希望在随机包中定义特定的随机数生成器时,才需要这个。
如果您不需要速度,也没有任何关于发行版的特定需求-如果您有任何需求,您可能会知道-那么请使用new BigInteger(n, new SecureRandom())

实施Random

TL;DR:不要
Random类已经被重构为一个实现接口的类。这意味着你可以在接口指定RandomGenerator的任何地方使用旧的Random。然而,这并不能反过来工作。
Random本身不是final类,所以可以从继承,所以可以原则上通过简单地实现Random中的所有方法并调用 Package 的RandomGenerator的类似命名的方法来创建适配器类。然而,这是非常危险的做法,因为Random的未来扩展可能会破坏一切。在最坏的情况下,它将通过混合父Random对象和 Package 的RandomGenerator的状态来显示不一致的行为。

迁移到Java 19

在Java 19(构建版本b21)中,为RandomGenerator提供了一个适配器方法,名为Random#from(RandomGenerator),您可以看到特性请求here。优选地,X1 M20 N1 X方法应当被改进以使用X1 M21 N1 X(如特征请求中所述)。
注意如果你怀疑setSeed可能被调用,你应该 * 永远不要 * 使用这个 Package 类,例如当在BigInteger类中生成一个大素数时。如果它被调用,它将生成一个UnsupportedOperationException
这类类类经过了各种测试,因此Java提供的方法是可信的。然而,一个方法可以被改造以使用setSeed的事实可能是一个关于向前兼容性的问题--你已经被警告过了。

[0, n^2)的特例

但是,你已经有一个了:范围0..2^n-1[0, 2^n-1)是一个由一组位组成的数,所以你可以使用你的RandomGenerator,填充一个字节数组,从第一个字节中删除最重要的位(因为Java是big endian),然后将数组转换成一个有符号整数:

/**
 * Mimics the {@link BigInteger#BigInteger(int, Random)} function using a
 * {@link RandomGenerator} instance.
 * 
 * @param numBits maximum bitLength of the new BigInteger.
 * @param rnd     source of randomness to be used in computing the new
 *                BigInteger.
 * @throws IllegalArgumentException {@code numBits} is negative.
 * @see #bitLength()
 */
public static BigInteger generateRandomBigInteger(int numBits, RandomGenerator rng) {
    if (numBits < 0) {
        throw new IllegalArgumentException("numBits must be non-negative");
    }

    if (numBits == 0) {
        return BigInteger.ZERO;
    }

    int bytes = (numBits + Byte.SIZE - 1) / Byte.SIZE;
    // mask bits that we need the value of to 1, the others - if any -- will be set
    // to zero
    byte bitMask = (byte) ((1 << ((numBits - 1) % Byte.SIZE + 1)) - 1);
    byte[] randomBytes = new byte[bytes];
    rng.nextBytes(randomBytes);
    randomBytes[0] &= bitMask;
    return new BigInteger(1, randomBytes);
}

numBits当然与您的n变量相同。

[0,max)的大小写

实际上,您可以将比较函数和随机位生成器组合在一起,这样您就可以创建范围为0..max的大随机值,其中max具有 * 任意值 *,随机位的数量最少,并且根本不需要讨厌的BigInteger操作(例如除法)。
你可以找到我对那个here的实现,但你可能会觉得奇怪。事先抱歉,是的,这是我的RNGBC算法的无耻插件:)

相关问题