我有一个组合问题,我希望能够随机选择一个介于0和一个大整数之间的整数。

我当前方法的不足之处
现在,对于常规整数,我通常会编写类似int rand 500;的东西并完成它。
但是对于大整数,看起来rand并非为此目的。
使用以下代码,我对rand $bigint进行了200万次调用的模拟:

$ perl -Mbigint -E 'say int rand 1230138339199329632554990773929330319360000000 for 1 .. 2e6' > rand.txt

结果集的分布远非理想的:

0(56个计数)
震级1e + 040(112个计数)
震级1e + 041(1411个计数)
1e + 042级(14496个计数)
震级1e + 043(146324计数)
震级1e + 044(1463824个计数)
1e + 045级(373777计数)

因此,该过程永远无法选择9995e+020之类的数字,这使此方法不适合我要执行的操作。
看起来这与rand的任意精度有关,在我的测试过程中,精度从未超过15位:
$ perl -E 'printf "%.66g", rand'
0.307037353515625


如何克服此限制?
我最初的想法是,也许有一种方法可以影响rand的精度,但是它感觉像是一个创可贴,可以解决更大的问题(即rand无法处理大整数)。
无论如何,我希望有人以前走过这条路,并且知道如何解决这种情况。

最佳答案

(从我的评论转换)

一种更受理论驱动的方法是使用对PRNG的多次调用来创建足够的随机位供您的数字进行采样。如果某些PRNG产生的位数不等于下面概述的所需位数,则必须小心!

伪码


计算代表您的数字所需的位:n_needed_bits
检查PRNG返回的位大小:n_bits_prng
计算所需的样本数:needed_prng_samples = ceil(n_needed_bits / n_bits_prng)
虽然为真:


采样needed_prng_samples(调用PRNG)时间并连接所有获得的位
检查结果数字是否在您的范围内
是?:返回编号(已完成)
否?:什么也不做(循环继续;将再次对所有组件重新采样!)



备注


这是acceptance-sampling / rejection-sampling的一种形式
方法是Las-vegas type of algorithm:理论上不受运行时的限制


平均需要的循环数:n_possible-sample-numbers-of-full-concatenation / n_possible-sample-numbers-within-range

根据拒绝方法进行完整的重采样(如果结果不在范围内),可以进行更正式的非偏置/均匀性分析,这对于此方法而言非常重要
当然,要使这项工作需要有关PRNG输出的经典假设。


例如,如果PRNG在低位/高位方面(如常提到的)有一些不均匀性,则会对上面的输出产生影响

关于perl - 如何选择0到bigint之间的随机值?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39958739/

10-09 06:03