当前位置:  开发笔记 > 编程语言 > 正文

从C到Java的随机发生器端口?

如何解决《从C到Java的随机发生器端口?》经验,为你挑选了3个好方法。

George Marsaglia编写了一个优秀的随机数发生器,它非常快速,简单,并且具有比Mersenne Twister高得多的周期.这是带有描述的代码:

好的C随机数发生器

我想将CMWC4096代码移植到Java,但它使用了几种无符号数据类型,因此我不确定如何正确执行此操作.这是完整的C代码:

/* choose random initial c<809430660 and */
/* 4096 random 32-bit integers for Q[]   */
static unsigned long Q[4096],c=362436;

unsigned long CMWC4096(void) {
    unsigned long long t, a=18782LL;
    static unsigned long i=4095;
    unsigned long x,r=0xfffffffe;
    i = (i+1) & 4095;
    t = a*Q[i] + c;
    c = (t>>32);
    x = t + c;
    if (x < c) {
        x++;
        c++;
    }
    return (Q[i] = r - x);
}

任何人都可以将其移植到Java吗?当您只有签名号码时,这是如何工作的?

编辑:谢谢大家快速解答!对于前1亿个数字,这个java代码似乎产生与C代码相同的结果.它比Java的java.util.Random快3倍.

public class ComplimentaryMultiplyWithCarryRandom {

    /**
     * Choose 4096 random 32-bit integers
     */
    private long[] Q;

    /**
     * choose random initial c<809430660
     */
    private long c = 362436;

    private int i;

    public ComplimentaryMultiplyWithCarryRandom() {
        Random r = new Random(1);
        Q = new long[4096];

        // TODO initialize with real random 32bit values
        for (int i = 0; i < 4096; ++i) {
            long v = r.nextInt();
            v -= Integer.MIN_VALUE;
            Q[i] = v;
        }
        i = 4095;
    }

    int next() {
        i = (i + 1) & 4095;
        long t = 18782 * Q[i] + c;
        c = t >>> 32;
        long x = (t + c) & 0xffffffffL;
        if (x < c) {
            ++x;
            ++c;
        }

        long v = 0xfffffffeL - x;
        Q[i] = v;
        return (int) v;
    }
}

starblue.. 43

大多数情况下,不需要使用较大的数字类型来模拟Java中的无符号类型.

对于加法,减法,乘法,左移,逻辑运算,等式和转换为较小的数字类型,无论操作数是有符号还是无符号,结果都是相同的,无论如何都被视为位模式.

如果转移到正确使用>> for signed,>>> for unsigned.

对于更大类型的签名转换,只需执行此操作即可.

对于从较小类型到长期使用的无符号转换,对于较小类型,使用类型为long的掩码.例如,短到长:s&0xffffL.

对于从较小类型到int的无符号转换和使用int类型的掩码.例如,byte到int:b&0xff.

否则在int情况下喜欢并在顶部应用强制转换.例如,字节到短:(短)(b和0xff).

对于比较运算符

1> starblue..:


大多数情况下,不需要使用较大的数字类型来模拟Java中的无符号类型.

对于加法,减法,乘法,左移,逻辑运算,等式和转换为较小的数字类型,无论操作数是有符号还是无符号,结果都是相同的,无论如何都被视为位模式.

如果转移到正确使用>> for signed,>>> for unsigned.

对于更大类型的签名转换,只需执行此操作即可.

对于从较小类型到长期使用的无符号转换,对于较小类型,使用类型为long的掩码.例如,短到长:s&0xffffL.

对于从较小类型到int的无符号转换和使用int类型的掩码.例如,byte到int:b&0xff.

否则在int情况下喜欢并在顶部应用强制转换.例如,字节到短:(短)(b和0xff).

对于比较运算符


好总结.虽然您忘记了一个关键操作:转换为更大的类型.(例如,将32位转换为64位#.)您需要使用掩码对结果进行AND运算,以便将原始对象解释为"无符号".
我当时没有这样看,但你是对的.没有掩码,演员签名,掩码未签名.通常你甚至不需要显式转换,因为合适的值会扩大.

2> Jason S..:

任何人都可以将其移植到Java吗?当您只有签名号码时,这是如何工作的?

无压力!a=18782因此,最大的t可能不会大到导致签名和未签名的问题.在任何地方使用Q之前,您必须将使用Q的结果"升级"为等于32位无符号数的值.例如,如果Q是int(32位有符号),那么在t=a*Q[i]+c语句中使用它之前必须这样做,例如

t=a*(((long)Q[i])&0xffffffffL)+c

其中(((long)Q [i])&0xffffffffL)业务将Q [i]提升为64位#并确保其高32位为0.(编辑:注意:你在这里需要0xffffffffL.如果你使用0xffffffff,Java会做错事,看起来它会将自己"优化"到错误的答案,如果Q [i]的高位为1,你会得到一个负数. )

您应该能够通过运行C++和Java中的算法来验证这一点,以比较输出.

编辑:这是一个镜头.我尝试用C++和Java运行它,N = 100000; 他们都匹配.抱歉,如果我使用了糟糕的Java习语,我仍然是Java的新手.

C++:

// marsaglia2003.cpp 

#include 
#include  // for atoi

class m2003
{
    enum {c0=362436, sz=4096, mask=4095};
    unsigned long Q[sz];
    unsigned long c;
    short i;

public:
    m2003()
    {
        // a real program would seed this with a good random seed
        // i'm just putting in something that makes the output interesting
        for (int j = 0; j < sz; ++j)
            Q[j] = j + (j << 16);
        i = 4095;
        c = c0;
    }

    unsigned long next()
    {
        unsigned long long t, a=18782LL;
        unsigned long x;
        unsigned long r=0xfffffffe;
        i = (i+1)&mask;
        t=a*Q[i]+c;
        c=(unsigned long)(t>>32);
        x=(unsigned long)t + c;
        if (x 1)
        n = atoi(argv[1]);

    for (int i = 0; i < n; ++i)
    {
        printf("%08x\n", generator.next());
    }
    return 0;
}

java :(比编译的C++慢,但匹配N = 100000)

// Marsaglia2003.java

import java.util.*;

class Marsaglia2003
{
    final static private int sz=4096;
    final static private int mask=4095;
    final private int[] Q = new int[sz];
    private int c=362436;
    private int i=sz-1;

    public Marsaglia2003()
    {
        // a real program would seed this with a good random seed
        // i'm just putting in something that makes the output interesting
        for (int j = 0; j < sz; ++j)
            Q[j] = j + (j << 16);
    }

  public int next() 
    // note: returns a SIGNED 32-bit number.
    // if you want to use as unsigned, cast to a (long), 
    // then AND it with 0xffffffffL
    {
        long t, a=18782;
        int x;
        int r=0xfffffffe;
        i = (i+1)&mask;
        long Qi = ((long)Q[i]) & 0xffffffffL; // treat as unsigned 32-bit
        t=a*Qi+c;
        c=(int)(t>>32); 
           // because "a" is relatively small this result is also small

        x=((int)t) + c;
        if (x=0) // tweak to treat x as unsigned
        {
            x++;
            c++;
        }
        return (Q[i]=r-x);
    }

    public static void main(String args[])
    {
        Marsaglia2003 m2003 = new Marsaglia2003();

        int n = 100;
        if (args.length > 0)
            n = Integer.parseInt(args[0]);
        for (int i = 0; i < n; ++i)
        {
            System.out.printf("%08x\n", m2003.next());
        }
    }
};



3> Dan Dyer..:

如果要在Java中实现RNG,最好对java.util.Random类进行子类化并覆盖受保护的next(int)方法(您的RNG是java.util.Random的替代品) ).下一个(int)方法涉及随机生成的位,而不是那些位可能代表的值.java.util.Random的其他(公共)方法使用这些位来构造不同类型的随机值.

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有