关于随机:用GETINT(INTN)方法获取Java的RNG种子

Get seed of Java's RNG with getInt(int n) method

我对Java RNG是如何工作的很感兴趣。我已经了解到使用getLong()方法非常简单,并且使用getInt()和两个值。我有兴趣用getInt(int n)获得种子,因为我知道n的价值。

因为getInt(n)通常使用val = bits % n;重复,直到bits - val + (n-1) >= 0)位,是next(31)位,所以val==位(mod n)

我测试了一个残差测试,测试了所有与初始值一致的可设置位置的数字对,但这对于计算机来说是非常长和困难的。

关于如何有效地获得种子还有其他想法吗?


您应该能够使用反射:

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
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) {
}

我的机器上的输出:

1
2
3
4
seed: 25214903916
mask: 281474976710655
multiplier: 25214903917
restored initial seed: 1

当设置seed时,值被置乱:

1
2
3
4
5
6
7
8
9
10
11
12
13
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
}

但是,maskmultiplier的定义如下:

1
2
private static final long mask = (1L << 48) - 1;
private static final long multiplier = 0x5DEECE66DL;

由于mask都是1s,对于最低有效48位,xor是可逆的,所以如果(并且只有当!)小于(1L<48),即2^48:

输出:

1
2
3
4
5
6
Random r = new Random((1L << 48)-1);

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

以及:

1
2
3
4
5
6
Random r = new Random((1L << 48));

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

另请参见StackOverflow上的这个答案