Java 线性同余发生器输出错误

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;

我创建了一个线性同余生成器(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;
    
    // 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());
    }
}