代码之家  ›  专栏  ›  技术社区  ›  Rob Cooper

测试随机值-对这种方法的思考?

  •  8
  • Rob Cooper  · 技术社区  · 17 年前

    好吧,我一直在研究一个随机的图像选择器和队列系统(所以你不会经常看到相同的图像)。

    一切进展顺利(就我那蹩脚的代码而言) 直到 我到了随机位。我想测试一下,但你怎么测试呢?没有 Debug.Assert(i.IsRandom) (可悲地):D

    所以,我喝了点茶,脑子里就想起来了,我想知道我能不能听听你的想法?

    • 基本上我知道 随机的 问题出在位上,所以我将其分解为委托(然后将其传递给对象构造函数)。
    • 然后我创建了一个类,它执行的逻辑与 居住 代码,但记住在专用变量中选择的值。
    • 然后我把那个代表扔到实况课堂上,并进行了测试:

    Debug.Assert(myObj.RndVal == RndIntTester.ValuePassed);
    

    但我忍不住想, 我是在浪费时间吗? 我重复了很多次,看看它是否会在任何时候失效。

    你认为我是在浪费时间吗?或者我能逃脱:

    Awesome Random Number Generator

    GateKiller's answer 提醒我:

    Dilbert Random

    更新以澄清

    • 我应该补充一点,我基本上不想看到同一个结果超过x次从一个Y大小的池。
    • 添加测试容器基本上允许我查看以前选择的图像是否是“随机”选择的。
    • 我想从技术上讲,这里测试的不是RNG(因为我从未写过代码),而是我所期望的事实 随机的 来自有限池的结果,我想跟踪它们。
    19 回复  |  直到 14 年前
        1
  •  6
  •   Amy B    17 年前

    根据要求进行测试:“所以你不会太频繁地看到相同的图像。”

    要求100张图片。你经常看到图像吗?

        2
  •  6
  •   moonshadow    17 年前

    有一个方便的清单 statistical randomness 试验和 related research 在维基百科上。请注意,您不一定知道某个数据源与大多数数据源是真正随机的,您只是排除了一些容易预测的方法。

        3
  •  5
  •   erickson    17 年前

    如果您有一组固定的项目,并且您不希望它们重复太多,那么随机地对集合进行洗牌。然后,你将确保你不会连续两次看到同一张图片,感觉你在听前20名的收音机,等等。在重复之前,你将对该收藏进行完整的浏览。

    Item[] foo = …
    for (int idx = foo.size(); idx > 1; --idx) {
      /* Pick random number from half-open interval [0, idx) */
      int rnd = random(idx); 
      Item tmp = foo[idx - 1];
      foo[idx - 1] = foo[rnd];
      foo[rnd] = tmp;
    }
    

    如果您有太多的项目需要一次收集和洗牌(存储库中有10万张图片),您可以在相同的方法中添加一些分而治之的方法。随机播放一组图像,然后随机播放每个组。

    一个听起来可能适用于修改后的问题语句的稍有不同的方法是让“图像选择器”实现将其最近的选择历史记录最多保留在一个队列中。 Y 长度。在返回图像之前,它将测试其是否在队列中 X 时间已经到了,如果是这样,它会随机选择另一个,直到找到一个通过。

    如果你真的想测试随机数生成器的质量,我得打开统计手册。

        4
  •  4
  •   Adam Rosenfield    17 年前

    不可能测试一个值是否真的是随机的。你能做的最好的就是做大量的测试,然后测试你得到了一个适当的分布,但是如果结果是随机的,即使这有一个(非常小的)失败的机会。

    如果您正在进行白盒测试,并且知道您的随机种子,那么您实际上可以计算预期的结果,但是您可能需要单独的测试来测试RNG的随机性。

        5
  •  2
  •   Steve Jessop    17 年前

    随机数的产生是 太重要了,不能放过机会。--罗伯特·R·科维尤

    解决心理问题:

    防止明显重复的一个不错的方法是从完整的集合中随机选择一些项目,丢弃重复项。播放这些,然后再选择几个。“少数”是多少取决于你玩它们的速度和整套游戏的大小,但例如,避免在“20”中的较大值内重复,“5分钟”可能是可以的。做用户测试——作为一个程序员,你会厌倦幻灯片,因为你不是一个好的测试对象。

    为了测试随机化代码,我会说:

    步骤1:指定代码必须如何将原始随机数映射到域中的选项,并确保代码正确使用随机数生成器的输出。通过模拟生成器来测试这一点(如果是prng,则为其设定已知的测试值)。

    第2步:确保生成器对于您的目的足够随机。如果使用了库函数,可以通过阅读文档来实现。如果你自己写,为什么?

    步骤3(仅限高级统计员):对生成器的输出运行一些随机性统计测试。确保您知道测试中出现错误失败的概率。

        6
  •  2
  •   Ian    17 年前

    有整本书,你可以写关于随机性和评估如果有的话 出现 随机的,但我会把数学的篇幅留给你。简而言之,您可以使用 chi-square test 作为确定一个明显的“随机”分布是否符合您的期望的一种方法。

    如果您使用的是Perl,那么可以使用 Statistics::ChiSquare 模块为您做艰苦的工作。

    但是,如果要确保图像均匀 分布式的 那么你可能不希望他们真的是随机的。相反,我建议你拿下你的整个图像列表,洗牌,然后从中删除一个项目,每当你需要一个“随机”的图像。当列表为空时,您重新构建它,重新洗牌,然后重复。

    这种技术意味着,给定一组图像,每个单独的图像不能在列表中的每个迭代中出现一次以上。你的图像只能均匀分布。

    最好的,

    保罗

        7
  •  1
  •   Joe Pineda    17 年前

    什么 随机的 类似的函数给你的只是伪随机数,一系列通过函数产生的数字。通常,给这个函数它是第一个输入参数(也就是“seed”),用来产生第一个“随机”数。之后,每个最后一个值被用作循环下一次迭代的输入参数。你可以查阅维基百科关于“伪随机数生成器”的文章,这里的解释很好。

    所有这些算法都有一些共同点: 序列在多次迭代后重复自身 . 记住,这些不是真正的随机数,只是一系列 似乎 随机的。要选择一个发电机而不是另一个,你需要问问自己:你想要它做什么?

    你如何测试随机性?确实可以。对此有很多测试。第一个也是最简单的是,当然,运行伪随机数生成器无数次,并编译每个结果出现的次数。最后,每个结果应该出现多次,非常接近(迭代次数)/(可能的结果数)。标准偏差越大,发电机就越差。

    第二个问题是:你当时使用的随机数是多少?2, 3?把它们成对(或三个部分)重复上一个实验:在很长的迭代次数之后,每个预期的结果应该至少出现一次,并且每个结果出现的次数不应该离预期太远。有些发电机一次只能使用一个或两个发电机,但在使用三个或更多发电机时会发生严重故障(Randu有人吗?).

    还有其他更复杂的测试:一些测试涉及到以对数比例绘制结果,或者将结果绘制到一个中间有一个圆的平面上,然后计算出有多少图落在其中,其他测试……我相信这2个应该足够大部分时间(除非你是一个挑剔的数学家)。

        8
  •  0
  •   GateKiller    17 年前

    随机就是随机的。即使同一张图片连续出现4次,也可以认为是随机的。

        9
  •  0
  •   Jason Z    17 年前

    我的观点是任何随机的东西都不能被适当地测试。

    当然,您可以尝试测试它,但是有这么多的组合可以尝试,您最好只依靠RNG和抽查大量案例。

        10
  •  0
  •   dguaraglia    17 年前

    问题是随机数的定义 可以 重复(因为它们…等待:随机)。也许你想做的是保存最新的随机数,并将计算出的随机数与该随机数进行比较,如果相等,就计算出另一个随机数…但现在你的数字是 较少随机 (我知道没有“或多或少”的随机性,但这次我就用这个词),因为它们肯定不会重复。

    无论如何,你不应该给随机数太多的思考。:)

        11
  •  0
  •   pkaeding    17 年前

    正如其他人所指出的,要真正检验随机性是不可能的。您可以(并且应该)将随机性包含到一个特定的方法中,然后为每个其他方法编写单元测试。这样,您就可以测试所有其他功能,假设您可以从最后一部分中得到一个随机数。

        12
  •  0
  •   vicky    17 年前

    存储随机值,在使用下一个生成的随机数之前,请检查存储的值。

        13
  •  0
  •   mes5k    17 年前

    任何一个好的伪随机数生成器都会让您为生成器播种。如果用相同的数字给生成器种子,那么生成的随机数流将是相同的。那么,为什么不为随机数生成器设定种子,然后根据特定的数字流创建单元测试呢?

        14
  •  0
  •   bram    17 年前

    要获得一系列非重复随机数:

    1. 创建随机数列表。
    2. 给每个随机数加一个序列号
    3. 按原始随机数对排序列表进行排序
    4. 将序列号用作新的随机数。
        15
  •  0
  •   Illandril    17 年前

    不要测试随机性,测试一下你得到的结果是否是可取的(或者,更确切地说,在接受你的结果可能是可取的之前,试着得到一些不可取的结果)。 如果要测试随机输出,就不可能确保永远不会得到不希望得到的结果,但至少可以增加您注意到它发生的机会。

    我要么选择n个Y大小的池,检查出现超过x次的结果,要么选择一个N*Y大小的池,检查Y大小的每组是否出现超过x次的结果(1到y,2到y+1,3到y+2等)。n值取决于您希望测试的可靠性。

        16
  •  0
  •   jschultz    17 年前

    随机数是由分布生成的。在这种情况下,每个值都应该具有相同的显示属性。如果你计算出无限多的随机数,你就能得到精确的分布。

    在实践中,多次调用函数并检查结果。如果您希望有n个图像,请计算100*n个随机数,然后计算找到每个期望数的数量。大多数应该出现70-130次。用不同的随机种子重新运行测试,看看结果是否不同。

    如果你发现你现在使用的发电机不够好,你可以很容易地找到一些东西。谷歌搜索“Mersenne Twister”——这比你需要的随机性要多得多。

    为了避免图像重新出现,你需要一些不那么随机的东西。一个简单的方法是检查不允许的值,如果它是其中之一,则重新计算。

        17
  •  0
  •   C. Dragon 76    17 年前

    虽然您不能测试随机性,但是您可以测试它是否与一个数字序列相关或分布。

    难以测试的目标:每次我们需要一个图像时,随机选择4个图像中的1个。

    易于测试的目标:对于我们选择的每100个图像,4个图像中的每一个必须至少出现20次。

        18
  •  0
  •   Jeremy Bourque    17 年前

    我同意亚当·罗森菲尔德的观点。对于你所说的情况,你唯一能有效测试的就是分布在整个范围内。

    我通常遇到的情况是,我用我最喜欢的语言prng生成伪随机数,然后将它们控制在所需的范围内。为了检查我的操作是否影响了分布,我生成了一组数字,操作它们,然后检查结果的分布。

    为了得到一个好的测试,您应该生成比您的范围所能容纳的数字多至少几个数量级的数字。使用的值越多,测试就越好。显然,如果你有一个非常大的范围,这将不起作用,因为你将不得不产生太多的数字。但在你的情况下,它应该可以正常工作。

    下面是Perl中的一个示例,说明了我的意思:

    for (my $i=0; $i<=100000; $i++) {
       my $r = rand;        # Get the random number
       $r = int($r * 1000); # Move it into the desired range
       $dist{$r} ++;        # Count the occurrences of each number
    }
    
    print "Min occurrences: ", (sort { $a <=> $b } values %dist)[1], "\n";
    print "Max occurrences: ", (sort { $b <=> $a } values %dist)[1], "\n";
    

    如果最小值和最大值之间的分布很小,则分布良好。如果它很宽,那么你的分布可能不好。您还可以使用此方法检查是否覆盖了您的范围以及是否遗漏了任何值。

    同样,生成的数字越多,结果越有效。我开始的时候比较小,工作到我的机器能在合理的时间内处理的任何事情,比如五分钟。

        19
  •  0
  •   not-bob    17 年前

    假设您正在测试整数中的随机性范围,验证这一点的一种方法是创建一个gajillion(好吧,可能是10000左右)“随机”数字,并将它们的出现情况绘制在柱状图上。

              ******    ******           ****
    ***********************************************
    *************************************************
    *************************************************
    *************************************************
    *************************************************
    *************************************************
    *************************************************
    *************************************************
    *************************************************
             1         2         3         4         5
    12345678901234567890123456789012345678901234567890
    

    上面显示了一个“相对”正态分布。

    如果它看起来更歪斜,例如:

              ******    ******           ****
        ************  ************  ************
        ************  ************  ***************
        ************  ************  ****************
        ************  ************  *****************
        ************  ************  *****************
       ***************************  ******************
       **************************** ******************
    ******************************* ******************
    **************************************************
             1         2         3         4         5
    12345678901234567890123456789012345678901234567890
    

    这样你就可以看到随机性少了。正如其他人提到的,还有重复的问题需要解决。

    如果要从生成器中编写一个包含10000个随机数的二进制文件,请使用1到1024之间的随机数,并尝试使用某种压缩(zip、gzip等)压缩该文件,那么可以比较两个文件的大小。如果有“大量”的压缩,那么它就不是特别随机的。如果尺寸变化不大,那就是“相当随机”。

    为什么会这样

    压缩算法寻找模式(重复或其他),并以某种方式减少。查看这些压缩算法的一种方法是测量文件中的信息量。高度压缩的文件几乎没有信息(例如随机性),而少量压缩的文件则有很多信息(随机性)。