Java 线性同余发生器输出错误
我创建了一个线性同余生成器(LCG),但它似乎给了我错误的输出Java 线性同余发生器输出错误,java,lcg,Java,Lcg,我创建了一个线性同余生成器(LCG),但它似乎给了我错误的输出 // Instance variables private long currentRandomNumber; private long a; private long c; private long m; public static void main(String[] args) { // perform calculations and tests here final long seed = 99L;
// Instance variables
private long currentRandomNumber;
private long a;
private long c;
private long m;
public static void main(String[] args) {
// perform calculations and tests here
final long seed = 99L;
// Java's java.util.Random class values (according to Wikipedia):
long a = 25214903917L;
long c = 11L;
long m = 2^48L;
LCG lcg = new LCG(a, c, m, seed);
System.out.println("Sequence of LCG class: " + lcg.nextRandom() + ", " + lcg.nextRandom() + ", " + lcg.nextRandom() + ", " + lcg.nextRandom() + ", " + lcg.nextRandom());
}
public LCG(long seed, long a, long c, long m) {
currentRandomNumber = seed;
this.a = a;
this.c = c;
this.m = m;
}
// Implementation of the recurrence relation of the generator
public long nextRandom() {
currentRandomNumber = (a * currentRandomNumber + c) % m;
return currentRandomNumber;
}
我得到的结果是:
Sequence of LCG class: 28, 61, 28, 61, 28
我使用了a、c和m的这些值,因为我读到java.util.Random类也使用这些值。但是使用同一种子的这个类给出了不同的答案。我还检查了其他lcg计算器,我的答案也不匹配。我不知道出了什么问题。LCG需要一个大模数
其中一个关键是m
应该足够大。或者,您可以快速找到重复的子序列,因为模运算总是为任何算术级数生成重复的子序列。然而,如果足够大,重复的子序列本身将非常长,因此看起来不会重复
你的
他50岁<代码>^没有达到您期望的效果。它是2异或48,而不是2乘以48的幂。所以使用
long m = 1L << 48; // or (long) Math.pow(2, 48)
为什么与java.util.Random不完全相同
根据我的经验,实现几乎总是伴随着启发式。下面是使用OpenJDK 15使用的启发式方法重新实现代码,以根据生成nextInt
eger。特别是根据
import java.lang.Math;
导入java.util.Random;
导入java.util.concurrent.AtomicLong;
类LCG{
私有原子数;
//私人长a;
//私人长c;
//私人长m;
专用整数位=32;
私有长加数=0xBL;//您的'c'在这里!
私有长掩码=(1L>>(48位));//您的'm'又在这里了
}
}
公共班机{
公共静态void main(字符串[]args){
长籽=99L;
长a=25214903917L;
长c=11L;
long m=(long)Math.pow(2,48);
LCG LCG=新LCG(种子、a、c、m);
随机随机=新随机(种子);
System.out.println(lcg.nextRandom());
System.out.println(random.nextInt());
}
}
如果使用OpenJDK 15编译代码,您将看到
lcg.nextRandom()
和random.nextInt()
生成相同的整数。在重新实现时,我发现较旧的OpenJDK使用了不同的启发式方法。调用构造函数的方式与定义构造函数的方式不同(“a,c,m,seed”与“long seed,long a,long c,long m”)2^48
。你为什么不直接输入50
?谢谢,但是在我匹配订单后,我仍然得到了错误的输出。现在我得到44,9,14,49,44请接受答案或留下评论以拒绝。谢谢,这确实解决了我的问题。不过,我还有一个后续问题。我在某个地方读到,我使用的数字与java.util.Random类使用的数字相同,但当我将它们相邻打印时,它们会有所不同。这怎么可能?我已经用Random.nextInt()和Random.nextLong()试过了。@Wilko我做了编辑。如果你有黑客的想法,就把它砍掉。请检查编辑并接受它。:)谢谢,这很有帮助。@Wilko也谢谢你,伙计:)
long m = 1L << 48; // or (long) Math.pow(2, 48)
Sequence of LCG class: 2496275487794, 103243855293781, 72264694917948, -37076138618729, -26695784318378
import java.lang.Math;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
class LCG {
private AtomicLong currentRandomNumber;
//private long a;
//private long c;
//private long m;
private int bits = 32;
private long addend = 0xBL; // your `c` is here!
private long mask = (1L << 48) - 1; // your `m` is here!
private long multiplier = 0x5DEECE66DL; // your `a` is here!
public LCG(long seed, long a, long c, long m) {
currentRandomNumber = new AtomicLong((seed ^ multiplier) & mask);
//this.a = a;
//this.c = c;
//this.m = m;
}
public long nextRandom() {
long oldseed, nextseed;
AtomicLong seed = this.currentRandomNumber;
do {
oldseed = seed.get();
nextseed = (oldseed * multiplier + addend) & mask;
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits)); // your `m` is here again
}
}
public class main {
public static void main(String[] args) {
long seed = 99L;
long a = 25214903917L;
long c = 11L;
long m = (long) Math.pow(2, 48);
LCG lcg = new LCG(seed, a, c, m);
Random random = new Random(seed);
System.out.println(lcg.nextRandom());
System.out.println(random.nextInt());
}
}