我有一个组合系统问题,我希望能够在0和一个大整数之间随机选择一个整数。
现在对于常规整数,我通常会编写类似int rand 500;
的内容并完成它。
但是对于大整数,看起来rand
不适合这个。
使用以下代码,我运行了对rand $bigint
的200万次调用的模拟:
$ perl -Mbigint -E 'say int rand 1230138339199329632554990773929330319360000000 for 1 .. 2e6' > rand.txt
结果集的分布远非理想:
因此,该流程永远无法选择999
或5e+020
这样的数字,这使得此方法不适合我想要做的事情。
看起来这与rand
的任意精度有关,在我的测试过程中它永远不会超过15位数:
$ perl -E 'printf "%.66g", rand'
0.307037353515625
我最初的想法是,可能有一种方法可以影响rand
的精确度,但感觉就像是一个更大问题的创可贴(即rand
无法处理大问题整数)。
无论如何,我希望有人之前走过这条路,知道如何纠正这种情况。
答案 0 :(得分:5)
(从我的评论中转换)
更理论化的方法是使用多次调用PRNG为您的数字创建足够的随机位进行采样。如果某个PRNG产生的比特数不等于下面所述的比特数,则必须小心!
n_needed_bits
n_bits_prng
needed_prng_samples = ceil(n_needed_bits / n_bits_prng)
needed_prng_samples
(致PRNG)时间&连接所有获得的位n_possible-sample-numbers-of-full-concatenation / n_possible-sample-numbers-within-range
答案 1 :(得分:3)
垃圾箱大小不一样。每个箱子的尺寸是前一个箱子的10倍。为了正确看待这一点,对于幅度为interviewed: true
的每个整数,有10,000个可能的整数1e+44
。
在1e+40
找到bigint的任意数量1e+20
的概率小于1e+45
。
在干草堆中忘记针,这更像是在类星体中寻找针!
答案 2 :(得分:1)
一种方法可以是将数字的字符串表示形式切割成块,初始化的布尔值($ low)为false,而第一次随机抽取等于上限。
编辑:在评论后添加了一些解释
# first argument (in) upper bound
# second argument (in/out) is lower (false while random returns upper bound, after it remains true)
sub randhlp {
my($upp)=@_;
my $l=length $upp;
# random number less than
# - upper bound if islower is false
# - 9..99 otherwise
my $x=int rand ($_[1] ? 10**$l : $upp+1);
if ($x<$upp) {
$_[1]=1;
}
# left padding with 0
return sprintf("%0*d",$l,$x);
}
# returns a random number less than argument (numeric string)
sub randistr {
my($n)=@_;
$n=~/^\d+$/ or die "invalid input not numeric";
$n ne "0" or die "invalid input 0";
my($low,$x);
do {
undef $x;
# split string by chunks of 6 characters
# except last chunk which has 1 to 6 characters
while ($n=~/.{1,6}/g) {
# concatenate random results
$x.=randhlp($&,$low)
}
} while ($x eq $n);
$x=~s/^0+//;
return $x;
}
测试
for ($i=0;$i<2e6;++$i) {
$H{length(randistr("1230138339199329632554990773929330319360000000"))}+=1;
}
print "$_ $H{$_}\n" for sort keys %H;
返回
39 4
40 61
41 153
42 1376
43 14592
44 146109
45 1463301
46 374404