Java 调整XORShift生成器以返回最大值内的数字
我需要在最大值内生成随机整数。由于性能至关重要,我决定使用XORShift生成器而不是Java的Random类Java 调整XORShift生成器以返回最大值内的数字,java,performance,random,Java,Performance,Random,我需要在最大值内生成随机整数。由于性能至关重要,我决定使用XORShift生成器而不是Java的Random类 long seed = System.nanoTime(); seed ^= (seed << 21); seed ^= (seed >>> 35); seed ^= (seed << 4); 实现此方法最有效的方法是什么?我对您的代码很感兴趣,并提出了以下建议: public class XORShiftRandom { private
long seed = System.nanoTime();
seed ^= (seed << 21);
seed ^= (seed >>> 35);
seed ^= (seed << 4);
实现此方法最有效的方法是什么?我对您的代码很感兴趣,并提出了以下建议:
public class XORShiftRandom {
private long last;
private long inc;
public XORShiftRandom() {
this(System.currentTimeMillis());
}
public XORShiftRandom(long seed) {
this.last = seed | 1;
inc = seed;
}
public int nextInt(int max) {
last ^= (last << 21);
last ^= (last >>> 35);
last ^= (last << 4);
inc += 123456789123456789L;
int out = (int) ((last+inc) % max);
return (out < 0) ? -out : out;
}
}
公共类XORShiftRandom{
私人长袍;
私人朗公司;
公共XORShiftRandom(){
这个(System.currentTimeMillis());
}
公共XORShiftRandom(长种子){
this.last=种子| 1;
inc=种子;
}
公共整数nextInt(整数最大值){
最后^=(最后>>35);
最后^=(最后一次播种)
这里有很多问题。如果你不止一次使用nanoTime
,你肯定会做错,因为nanoTime
很慢(数百纳秒)。此外,这样做可能会导致质量下降
让我们假设,你只给你的发电机播种一次
一致性
如果你关心均匀性,那么至少有两个问题:
异或移位
它永远不会生成零(除非你在播种时运气不好,然后你只能得到零)
这很容易通过以下简单的方法解决
private long nextLong() {
x ^= x << 21;
x ^= x >>> 35;
x ^= x << 4;
y += 123456789123456789L;
return x + y;
}
nextInt(整数限制)
由于我在a中提到的原因,接受的答案提供了非均匀分布的值。正确操作有点复杂,您可以从Random#nextInt
复制代码,也可以尝试类似的操作(未经测试):
public int nextInt(int limit){
检查参数(限制>0);
整数掩码=-1>>>整数。前导零的数目(限制);
while(true){
int result=(int)nextLong()&掩码;
if(结果<限制)返回结果;
}
}
上面,掩码
以二进制形式显示,类似于0…01…1
,其中最高的一个对应于限制
中的最高一个。使用它,可以生成范围0.掩码
内的均匀分布的数字(统一性很容易,因为掩码+1
是二的幂)。条件拒绝数不低于限制
。正如限制>掩码/2
,发生这种情况的概率低于50%,因此预期迭代次数低于2
推荐
这很有趣,但测试起来很难,我建议使用ThreadLocalRandom
,除非你需要再现性。你不能将长模化为最大值吗?@SajitKunnumkal这会对一些整数产生(轻微)偏差(当然,如果最大值足够小,可能可以忽略不计)。如果性能至关重要,则应避免使用nanoTime()
。如果性能至关重要,则可能应使用简单的LCG。如果max为常量且提前知道,则甚至可以构建一个临时LCG,该LCG将直接生成[0,max]范围内的数字没有偏见。使用XORShift时不应考虑性能;使用它的事实意味着它适用于非关键应用程序,这意味着System.nanoTime()非常合适。对移位值21、35、4有什么解释吗?也就是说,你有没有用其他值测试速度和/或随机性?这些值来自OP,我没有用它们。也许可以问他一个问题。这里可以快速讨论为什么这些值有用:注意(与java.util.Random
不同)您的结果不是完全均匀分布的。它们不能是2**32
(整数的数量)不能被max
整除,除了二的幂。对于真正大的max
如3e9
,比率是1:2,对于小的值,它要好得多。@maaartinus我认为这是一个非常重要的点,不应该被低估。我将要求解释为找到一种性能高效的方法来扩展result在不影响原始算法均匀分布特性的情况下达到所需范围。取模不能满足此要求。很好。感谢您花时间响应坚实方法的基础!
private long nextLong() {
x ^= x << 21;
x ^= x >>> 35;
x ^= x << 4;
y += 123456789123456789L;
return x + y;
}
seed = System.nanoTime();
x = seed | 1;
y = seed;
public int nextInt(int limit) {
checkArgument(limit > 0);
int mask = -1 >>> Integer.numberOfLeadingZeros(limit);
while (true) {
int result = (int) nextLong() & mask;
if (result < limit) return result;
}
}