python实现 LCG算法 生成与java.util.Random相同的随机数序列
java.util.Random中随机数生成方法
在Java中,java.util.Random类的内部实现主要基于伪随机数生成器
(Pseudorandom Number Generator,简称PRNG)。
具体来说,Random类使用了一个48位的随机数种子(seed),
并通过线性同余法(Linear Congruential Generator,简称LCG)生成伪随机数序列。
下面是Random类的简化版本的部分源码:
package java.util;
public class Random implements java.io.Serializable {
private static final long serialVersionUID = 3905348978240129619L;
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
private long seed;
public Random(long seed) {
this.seed = (seed ^ multiplier) & mask;
}
protected int next(int bits) {
seed = (seed * multiplier + addend) & mask;
return (int) (seed >>> (48 - bits));
}
public int nextInt() {
return next(32);
}
public int nextInt(int bound) {
if (bound <= 0)
throw new IllegalArgumentException("bound must be positive");
if ((bound & -bound) == bound) // i.e., bound is a power of 2
return (int) ((bound * (long) next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % bound;
} while (bits - val + (bound-1) < 0);
return val;
}
public long nextLong() {
return ((long) next(32) << 32) + next(32);
}
public double nextDouble() {
return (((long) next(26) << 27) + next(27)) * DOUBLE_UNIT;
}
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
public float nextFloat() {
return next(24) / ((float)(1 << 24));
}
public boolean nextBoolean() {
return next(1) != 0;
}
public double nextGaussian() {
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
double v1, v2, s;
do {
v1 = 2 * nextDouble() - 1; // between -1 and 1
v2 = 2 * nextDouble() - 1; // between -1 and 1
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s) / s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
private boolean haveNextNextGaussian = false;
private double nextNextGaussian;
// 其他方法...
}
在构造函数中,传递给构造函数的种子经过一系列位运算和算术运算后被存储在seed变量中。
next方法使用线性同余法更新seed并返回指定位数的伪随机数。
python实现与java对照
class JavaRandomCompat:
def __init__(self, seed=None):
if seed is None:
seed = (int((id(self) + id(seed)) * 997) & ((1 << 48) - 1))
self.seed = (seed ^ 0x5DEECE66D) & ((1 << 48) - 1)
def next(self, bits):
self.seed = (self.seed * 0x5DEECE66D + 0xB) & ((1 << 48) - 1)
value = self.seed >> (48 - bits)
return value if value < (1 << (bits - 1)) else value - (1 << bits)
def next_int(self):
return self.next(32)
def next_long(self):
return (self.next(32) << 32) + self.next(32)
def next_float(self):
return self.next(24) / (1 << 24)
def next_double(self):
return ((self.next(26) << 27) + self.next(27)) * (1.0 / (1 << 53))
# 使用示例
java_random_compat = JavaRandomCompat(seed=1)
for i in range(5):
print("随机整数:", java_random_compat.next_int())
python随机数种子2测试
java对照代码
import java.util.Random;
public class RandomExample {
public static void main(String[] args) {
Random random = new Random(1);
for (int i = 0; i < 5; i++) {
int randomNumber = random.nextInt();
System.out.println("Random number: " + randomNumber);
}
}
}
java随机数种子2测试
可以看到,生成的序列完全相同