Java 快速均匀分布随机数发生器

Java 快速均匀分布随机数发生器,java,performance,random,Java,Performance,Random,作为蒙特卡罗模拟的一部分,我必须掷一组骰子,直到某些值出现一定次数。我的代码调用一个dice类,该类生成一个介于1和6之间的随机数,并返回它。最初代码看起来像 public void roll() { value = (int)(Math.random()*6) + 1; } 而且速度不是很快。通过将Math.random()替换为 它在大约60%的原始时间内运行了一个部分,大约调用了2.5亿次。 作为整个模拟的一部分,它至少会调用此方法数十亿次,那么有没有更快的方法来实现这一点呢?选

作为蒙特卡罗模拟的一部分,我必须掷一组骰子,直到某些值出现一定次数。我的代码调用一个dice类,该类生成一个介于1和6之间的随机数,并返回它。最初代码看起来像

public void roll() {
    value = (int)(Math.random()*6) + 1;
}
而且速度不是很快。通过将Math.random()替换为

它在大约60%的原始时间内运行了一个部分,大约调用了2.5亿次。
作为整个模拟的一部分,它至少会调用此方法数十亿次,那么有没有更快的方法来实现这一点呢?

选择一个随机生成器,它的速度与您需要的速度一样快,并且不会因线程安全机制而降低到正常速度的一小部分。然后选择一种生成[1..6]整数分布的方法,该方法速度快,精度高

速度最快的简单发电机,其质量足以超过PRNG的标准测试,例如(而不是像Mersenne捻线机那样系统性地失败)是。我将它显示为C代码,但Sebastiano有:

uint64\u t异或移位64s(int64\u t&x)
{
x^=x>>12;
x^=x>27;
返回x*2685821657736338717ull;
}
有很多有用的信息、链接和基准测试结果。包括有数学倾向的论文

在这种高分辨率下,您可以简单地使用
1+xorshift 64s(state)%6
,并且偏差将非常小。如果速度不够快,则通过与逆数相乘来实现模除。如果这还不够快-如果你不能负担每个变量两个MUL-那么它会变得很棘手,你需要回到这里。(Java)加上变量的一些位技巧将是一种选择

批处理—生成一个充满数字的数组并进行处理,然后重新填充数组等等—可以释放一些速度储备。在课堂上不必要地包装东西会达到相反的效果

注意:如果ThreadLocalRandom和xorshift*对于您的目的来说,即使使用批处理,速度也不够快,那么您可能使用了错误的方式,或者使用了错误的语言。或者两者兼而有之


附言:在Java(或C#,或Delphi)等语言中,抽象不是免费的,它有成本。在Java中,您还必须考虑一些事情,比如强制性的免费数组边界检查,除非您有一个可以消除这些检查的编译器。挑逗Java程序的高性能可能会涉及到很多问题。。。在C++中,你可以免费获得抽象和性能。

< P>达思是正确的,XORSHIFT *可能是最好的生成器。使用它来填充一个字节的环形缓冲区,然后一次提取一个字节来掷骰子,在提取足够的字节后重新填充缓冲区。为了得到实际的模辊,通过使用拒收抽样避免分割和偏差。代码的其余部分如下所示(在C中):


这将允许您平均每64位随机值获得6个骰子滚动。

您的结果给了您一个提示:并行化应该扩展到整个算法,而不仅仅是骰子滚动。我不确定是否可以分块运行该算法,因为它运行的次数取决于滚动值,它可能在调用随机函数6次后终止算法是什么?正如duffymo所指出的,如果您在顶层划分工作,那么您可以让多个线程并行处理数字。在没有看到实际的算法/问题的情况下,我们只能提供一般性的建议和猜测。我知道,算法是取一组大小为n的骰子,掷骰子直到出现一个条件,当出现时,计算掷骰子的次数,并重复1000000次,我猜这可能是线程化的。结果是图形化的,因此迭代次数越多,结果越精确,图形效果越好。该图的重点是大致了解它的复杂度有多大。还有进一步的优化:首先,使用64位Xorshift用随机字节填充环形缓冲区,然后在实际滚动模具时一次抓取一个字节(实际上,您只需要三个随机位,但抓取字节可以消除大量移位和掩蔽). 然后,使用拒绝采样将3位值压缩到1..6。这将拒绝25%的字节,但它消除了除法,并且每通过一次64位的Xorshift,仍将获得6个转鼓。在C语言中,我可以在一分钟内模拟出几十亿只21点,这很好地解决了除法问题。然而,如果我们在这里谈论的是C/asm级别的性能,你会用它来换取25%的预测失误的机会,这大约是一个MUL的五倍。。。我希望有人真的需要每秒10^9个骰子卷,这样我们就有了超越极限的借口。:-)在任何情况下,你的解决方案都是非常非常难击败的。我喜欢。该死的东西不允许我编辑我的评论。。。我想将我对李的解决方案的评估修改为“芬达·弗里肯·塔斯蒂克,很可能是不可能击败的”。信用到期的地方。作者要求统一的随机数@DarthGizka,你能谈谈用xorshift生成这样的数字吗?@kelin:作者问到生成统一整数的性能,这正是我们一直在谈论的。如果你的问题是关于统一浮点数的生成,那就另当别论了,一条评论太短了,无法进行合理的处理(除了说需要小心,因为天真的方法往往会产生偏差的结果)。你真的应该把这个问题作为一个单独的问题来问——前提是还没有人问过。
ThreadLocalRandom.current().nextInt(1, 7);
uint64_t xorshift64s (int64_t &x)
{
   x ^= x >> 12;
   x ^= x << 25;
   x ^= x >> 27;

   return x * 2685821657736338717ull;
}
do {
    if (bp >= buffer + sizeof buffer) {
        // refill buffer with Xorshifts
    }
    v = *bp++ & 7;
} while (v > 5);
return v;