Random 在Julia中生成范围内随机整数的有效方法

Random 在Julia中生成范围内随机整数的有效方法,random,integer,julia,Random,Integer,Julia,我正在进行MC模拟,我需要生成介于1和可变上限n_mol 具体的Julia函数是rand(1:n_mol),其中n_mol是一个随着每次MC迭代而变化的整数。问题是这样做很慢。。。(可能是一个需要开发人员解决的问题)。因此,我没有使用特定的函数调用,而是考虑在[0,1]中生成一个随机浮点,将其乘以n_mol,然后得到结果的整数部分:int(rand()*n_mol)现在的问题是int()四舍五入,这样我可以得到介于0和n_-mol之间的数字,而我无法得到0…因此我目前使用的解决方案是使用iflo

我正在进行MC模拟,我需要生成介于
1
和可变上限
n_mol

具体的Julia函数是
rand(1:n_mol)
,其中
n_mol
是一个随着每次MC迭代而变化的整数。问题是这样做很慢。。。(可能是一个需要开发人员解决的问题)。因此,我没有使用特定的函数调用,而是考虑在[0,1]中生成一个随机浮点,将其乘以
n_mol
,然后得到结果的整数部分:
int(rand()*n_mol)
现在的问题是
int()
四舍五入,这样我可以得到介于
0
n_-mol
之间的数字,而我无法得到
0
…因此我目前使用的解决方案是使用
ifloor
并添加一个
1
ifloor(rand()*n_-mol)+1
,这比第一个要快得多,但比第二个慢得多

function t1(N,n_mol)
    for i = 1:N
        rand(1:n_mol)
    end
end

function t2(N,n_mol)
    for i = 1:N
        int(rand()*n_mol)
    end
end

function t3(N,n_mol)
    for i = 1:N
        ifloor(rand()*n_mol)+1
    end
end


@time t1(1e8,123456789)
@time t2(1e8,123456789)
@time t3(1e8,123456789)


elapsed time: 3.256220849 seconds (176 bytes allocated)
elapsed time: 0.482307467 seconds (176 bytes allocated)
elapsed time: 0.975422095 seconds (176 bytes allocated)
那么,有没有办法在速度接近第二次测试的情况下加快速度? 这一点很重要,因为MC模拟需要超过1e10次迭代。
结果必须是整数,因为它将用作数组的索引。

请注意,在0.4中,
int()
已被弃用,您需要使用
round()

function t2(N,n_mol)
  for i = 1:N
    round(rand()*n_mol)
  end
end
在我的机器上给出0.27秒(使用Julia 0.4)。

rand(r::Range)代码非常快,考虑到以下两个因素。首先,Julia调用52位rng两次以获得随机整数,调用52位rng一次以获得随机浮点,这在一些簿记中给出了因子2.5。第二件事是

(rand(Uint) % k) 
如果k是2的幂,则仅在0到k-1之间均匀分布。这与拒绝采样有关,这或多或少解释了剩余的额外成本

如果速度非常重要,您可以使用一个简单的随机数生成器作为Julia,并忽略这些问题。例如,使用无拒绝采样的线性同余生成器

function lcg(old) 
    a = unsigned(2862933555777941757)
    b = unsigned(3037000493)
    a*old + b
end

function randfast(k, x::Uint)
    x = lcg(x)
    1 + rem(x, k) % Int, x
end

function t4(N, R)
    state = rand(Uint)
    for i = 1:N
        x, state = randfast(R, state)
    end
end
但是要小心,如果范围(真的)很大

但是(!)


你看过Julia的MCMC库Lora.jl吗?要非常小心地实现你自己的快捷方式。我不是随机数专家,但我知道你可以通过修改随机数很容易地引入偏差。
t2
t3
都要求
n\mol≪ maxintfloat(Float64)
t2
会略微偏向于Julia 0.4上的偶数,因为它默认使用(讽刺的是,否?同样,随着
n\u mol
的增加,这种效果会更大)。谢谢你的建议!谢谢,我不知道
int()
在0.4中不推荐使用
round()由于某些原因,0.3.11中的
要慢得多。可能是在0.4中更改的。仍然不能真正使用它,因为如果
rand()*n_mol
请尝试使用
ceil(Int,rand()*n_mol)
:这将四舍五入并返回一个整数type@SimonByrne:
rand()
返回范围
[0,1)
。这可能是万亿次中的1次,但它可能返回0。如果我的弱小笔记本电脑使用
rand()
连续生成随机数,则可能每月发生一次。@SimonByrne我尝试过做ceil,但从测试2开始需要2倍的时间(至少在0.3.11中)谢谢!这看起来很有希望。我把计算简化了一点,而且我的
t2
函数几乎得到了一个更好的结果。范围不应该大于1e12,所以使用起来很安全。我不确定拒绝采样对我来说是否有问题,但我会检查一下,让你知道噢,谢谢。
m = div(typemax(Uint),3)*2

julia> mean([rand(1:m)*1.0 for i in 1:10^7])
6.148922790091841e18

julia> m/2
6.148914691236517e18
julia> mean([(rand(Uint) % m)*1.0 for i in 1:10^7])
5.123459611164573e18

julia> 5//12*tm
5.124095576030431e18