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).
对于比较运算符 大多数情况下,不需要使用较大的数字类型来模拟Java中的无符号类型. 对于加法,减法,乘法,左移,逻辑运算,等式和转换为较小的数字类型,无论操作数是有符号还是无符号,结果都是相同的,无论如何都被视为位模式. 如果转移到正确使用>> for signed,>>> for unsigned. 对于更大类型的签名转换,只需执行此操作即可. 对于从较小类型到长期使用的无符号转换,对于较小类型,使用类型为long的掩码.例如,短到长:s&0xffffL. 对于从较小类型到int的无符号转换和使用int类型的掩码.例如,byte到int:b&0xff. 否则在int情况下喜欢并在顶部应用强制转换.例如,字节到短:(短)(b和0xff). 对于比较运算符 任何人都可以将其移植到Java吗?当您只有签名号码时,这是如何工作的? 无压力! 其中(((long)Q [i])&0xffffffffL)业务将Q [i]提升为64位#并确保其高32位为0.(编辑:注意:你在这里需要0xffffffffL.如果你使用0xffffffff,Java会做错事,看起来它会将自己"优化"到错误的答案,如果Q [i]的高位为1,你会得到一个负数. ) 您应该能够通过运行C++和Java中的算法来验证这一点,以比较输出. 编辑:这是一个镜头.我尝试用C++和Java运行它,N = 100000; 他们都匹配.抱歉,如果我使用了糟糕的Java习语,我仍然是Java的新手. C++: java :(比编译的C++慢,但匹配N = 100000)
1> starblue..:
好总结.虽然您忘记了一个关键操作:转换为更大的类型.(例如,将32位转换为64位#.)您需要使用掩码对结果进行AND运算,以便将原始对象解释为"无符号".
我当时没有这样看,但你是对的.没有掩码,演员签名,掩码未签名.通常你甚至不需要显式转换,因为合适的值会扩大.
2> Jason S..:
a=18782
因此,最大的t
可能不会大到导致签名和未签名的问题.在任何地方使用Q之前,您必须将使用Q的结果"升级"为等于32位无符号数的值.例如,如果Q是int
(32位有符号),那么在t=a*Q[i]+c
语句中使用它之前必须这样做,例如t=a*(((long)Q[i])&0xffffffffL)+c
// marsaglia2003.cpp
#include
// 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
如果要在Java中实现RNG,最好对java.util.Random类进行子类化并覆盖受保护的next(int)方法(您的RNG是java.util.Random的替代品) ).下一个(int)方法涉及随机生成的位,而不是那些位可能代表的值.java.util.Random的其他(公共)方法使用这些位来构造不同类型的随机值.