使用Java的RNG获取种子,使用getInt(int n)方法。

3
我对Java RNG的工作原理非常感兴趣。我已经了解到使用getLong()方法和getInt()方法以及两个值非常容易。我想知道如何使用getInt(int n)方法获取种子,已知n的值。
由于getInt(n)通常使用val = bits % n;并重复此过程,直到bits - val + (n-1) >= 0),其中bits是next(31),因此val == bits (mod n)。
我已经尝试过暴力测试所有与初始值同余的数字对,但这对计算机来说非常耗时和困难。
还有其他方法可以高效地获取种子吗?

你在哪里看到使用 getLong 很容易?另外,你是指第一次调用 getInt 还是任意调用? - Julián Urbano
请翻译以下与编程相关的内容从英文到中文。只返回翻译后的文本:https://dev59.com/HGUp5IYBdhLWcg3wf3us 和不带参数调用getInt()两次。 - mcat
1个回答

2

您应该能够使用反射来实现此功能:

Random r = new Random(1);

Field f;
try {
    f = r.getClass().getDeclaredField("seed");
    f.setAccessible(true);
    AtomicLong seed = (AtomicLong) f.get(r);
    System.out.println("seed: " + seed);

    f = r.getClass().getDeclaredField("mask");
    f.setAccessible(true);
    Long mask = (Long) f.get(r);
    System.out.println("mask: " + mask);

    f = r.getClass().getDeclaredField("multiplier");
    f.setAccessible(true);
    Long multiplier = (Long) f.get(r);
    System.out.println("multiplier: " + multiplier);


    long initialSeed = (seed.longValue() ^ multiplier);
    System.out.println("restored initial seed: " + initialSeed);
} catch (NoSuchFieldException e1) {
} catch (SecurityException e2) {
} catch (IllegalAccessException e3) {
} catch (IllegalArgumentException e4) {
}   

我的机器上的输出:

seed: 25214903916
mask: 281474976710655
multiplier: 25214903917
restored initial seed: 1

当设置了seed时,值会被打乱:

public Random(long seed) {
    if (getClass() == Random.class)
        this.seed = new AtomicLong(initialScramble(seed));
    else {
        // subclass might have overriden setSeed
        this.seed = new AtomicLong();
        setSeed(seed);
    }
}

private static long initialScramble(long seed) {
    return (seed ^ multiplier) & mask; // (seed XOR multiplier) AND mask
}

然而,掩码乘数只是被定义为:
private static final long mask = (1L << 48) - 1;
private static final long multiplier = 0x5DEECE66DL;

由于掩码mask在最低有效的48位上都是1,并且异或操作是可逆的,因此只有当初始种子小于(1L << 48),即2^48时,才能获取回初始种子:

以下为输出结果:

Random r = new Random((1L << 48)-1);

seed: 281449761806738
mask: 281474976710655
multiplier: 25214903917
restored initial seed: 281474976710655

并且针对:

Random r = new Random((1L << 48));

seed: 25214903917
mask: 281474976710655
multiplier: 25214903917
restored initial seed: 0

请参阅StackOverflow上的此答案


当您拥有结果种子和执行的操作时,无法推断出原始种子吗? - Jeroen Vannevel
让我检查一下,如果初始种子小于2^48,那么这是可能的。 - jmiserez
2
请查看我的更新答案,了解如何获取初始种子值。 - jmiserez
增加了角落案例(1L << 48)-1(1L << 48)的输出。 - jmiserez
谢谢,这正是我在寻找的 :D - mcat
非常好的回答! - Jeroen Vannevel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接