Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Language agnostic 将伪随机数限制在较小范围内的正确方法是什么?_Language Agnostic_Random - Fatal编程技术网

Language agnostic 将伪随机数限制在较小范围内的正确方法是什么?

Language agnostic 将伪随机数限制在较小范围内的正确方法是什么?,language-agnostic,random,Language Agnostic,Random,将PRNG值限制在较小范围内的最佳方法是什么?如果使用模数,而旧的最大数不能被新的最大数平均整除,则会偏向0到(旧的最大数-新的最大数-1)。我认为最好的方法是这样的(这是浮点,不是整数数学) 但我内心深处的某种东西让我质疑这种方法(可能是浮点实现和表示的差异?) 随机数生成器将在硬件和软件平台上产生一致的结果,同时也需要考虑约束 我怀疑上面的伪代码是对的(但不是因为我想的原因)。迈克尔让我用另一种方式思考这个问题。我可以用更小的数字来建模,并测试每一个结果。假设我们有一个PRNG,它产生一个介

将PRNG值限制在较小范围内的最佳方法是什么?如果使用模数,而旧的最大数不能被新的最大数平均整除,则会偏向
0
(旧的最大数-新的最大数-1)
。我认为最好的方法是这样的(这是浮点,不是整数数学)

但我内心深处的某种东西让我质疑这种方法(可能是浮点实现和表示的差异?)

随机数生成器将在硬件和软件平台上产生一致的结果,同时也需要考虑约束

我怀疑上面的伪代码是对的(但不是因为我想的原因)。迈克尔让我用另一种方式思考这个问题。我可以用更小的数字来建模,并测试每一个结果。假设我们有一个PRNG,它产生一个介于0和31之间的随机数,你希望较小的范围是0到9。如果使用模数,则会偏向0、1、2和3。如果使用上面的伪代码,则会偏向0、2、5和7。我不认为有什么好方法可以把一组映射到另一组。到目前为止,我想到的最好方法是重新生成大于
old_max/new_max
的随机数,但这也有深层次的问题(缩短周期、生成新数的时间,直到一个数在正确的范围内,等等)


我想我可能是天真地处理了这个问题。也许是时候开始对文献进行认真的研究了(一定有人之前已经解决过这个问题)。

我知道这可能不是一个特别有用的答案,但我认为最好的方法是设想几种不同的方法,然后尝试数百万次,然后检查结果集

如果有疑问,请自己尝试

编辑

应该注意的是,许多语言(如C#)都内置了函数限制

int maximumvalue = 20;
Random rand = new Random();

rand.Next(maximumvalue);
只要有可能,您应该使用这些代码,而不是您自己编写的任何代码。不要重新发明轮子。

如果PRNG()正在生成均匀分布的随机数,那么上面的情况看起来不错。事实上(如果你想衡量平均值等),上述各方面都可以。我想您需要询问与原始PRNG()相关的错误是什么,以及进一步的操作是否会实质性地增加错误


如果有疑问,生成一个适当大小的样本集,并在Excel或类似软件中查看结果(检查您的平均值/std.dev等,了解您的期望值)

如果您可以访问PRNG函数(例如,random()),该函数将生成范围为0的数字,以下是CLR的随机类在受到限制时的工作方式(根据反射器):

long num=maxValue-minValue;

如果(numPsuedo随机数生成器基本上是生成一个由1和0组成的随机序列,当它们彼此相加时,在基数2中是一个无穷大的数字。每次你从prng中消耗一点,你就是将该数字除以2并保持模。你可以永远这样做,而不会浪费一点


如果您需要[0,N]范围内的数字,则需要相同的,但不是基数2,而是基数N。转换基数基本上很简单。消耗所需的位数,将这些位数的剩余部分返回到prng,以便下次需要某个数字时使用。

此问题类似于仅给定一个p面骰子滚动k面骰子,而不浪费随机数美国

从这个意义上说,根据B.Kloeckner的“”中的引理3,除非“每个素数除以k也除以p”,否则这种浪费是不可避免的。因此,例如,如果p是2的幂(并且任何随机位块都与滚动具有2个面的幂的模具相同)k有除2以外的主要因子,你能做的最好的就是任意接近,不浪费随机性,比如通过分批多卷的p面模具,直到p^n“足够接近”k的幂

我还要谈谈你对重新生成随机数的一些担忧:

  • “缩短周期”:除了对BIT进行批处理外,还可以通过以下几种方式处理此问题:
    • 使用a(最大循环长度)
    • 在PRNG的实施中添加一个
    • 使用“真”随机数生成器;这不是小事
    • 使用随机性抽取,这在我的和中进行了讨论。然而,随机性抽取涉及的内容非常多
    • 忽略这个问题,尤其是当它不是一个安全应用程序或严重的模拟时
  • “生成新数字直到一个在正确范围内的时间”:如果你想要无偏随机数,那么任何这样做的算法通常都必须在最坏的情况下永远运行。同样,通过引理3,该算法将在最坏的情况下永远运行,除非“每个素数除以k也除以p”,如果k为10,p为32,则情况并非如此

另请参见问题:,特别是我的答案。

问题中的PRNG生成一个介于0和2^32之间的数字,即使它生成了,我仍然担心浮点不准确会导致系统之间的问题(例如,1/10无法准确表示,因此一些实现选择.09…9和其他.10…01)您还可以看看java.util.Random.nextInt(int),它使用了一种非常聪明的方法来约束结果而不引入偏差。我花了大约一天的时间来理解它的工作原理:)该源代码在哪里可用(对不起,我不是java程序员,我不知道API在哪里)随机检查不是一个好主意,但如果我将数字减少到可管理的程度,我可以测试每个结果(见上文),而伪代码实际上是有偏差的。现在我必须仔细阅读我不太可能理解的文章,唉。嗯,如果我读对了,PRNG会生成浮点(if)或双精度(ou)
int maximumvalue = 20;
Random rand = new Random();

rand.Next(maximumvalue);
 random_num = (int) (random() * max_range);
long num = maxValue - minValue;
if (num <= 0x7fffffffL) {
    return (((int) (this.Sample() * num)) + minValue);
}
return (((int) ((long) (this.GetSampleForLargeRange() * num))) + minValue);