【问题标题】:c beginner rand()c 初学者 rand()
【发布时间】:2012-04-07 06:53:30
【问题描述】:

此代码连续 200 次第 1 次为 r 生成 1 结果;后来的投掷不是静态的;他们改变了;知道我搞砸了什么吗?使用 Xcode。谢谢!

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define tprop .5    // propability coin will be tails

int main(int argc, const char *argv[])
{
    int i;          // for loop counter
    int n;          // # of rolls
    int hc = 0;     // heads counter
    int tc = 0;     // tails counter
    int r;          // roll... 1=heads, 0=tails

    srand(time(NULL));  // seed Random# generator with current time

    printf("Enter # of times to toss a coin: ");
    scanf("%i", &n);

    for (i = 0; i < n; i++) {
        if ((float) rand() / RAND_MAX > tprop) {
            r = 1;
            hc++;
        } else {
            r = 0;
            tc++;
        }
        printf("%in", r);
    }
    printf("# of times heads came up: %i (%f%%)n", hc, (float) hc / n * 100);
    printf("# of times tails came up: %i (%f%%)n", tc, (float) tc / n * 100);

    return 0;
}

【问题讨论】:

  • 对于超过 100 次运行,第一次投掷导致正面;发生这种情况的可能性非常小,所以我假设某处存在问题......我从命令行运行它,而不是从 Xcode 运行 30 次,除了之前的运行,所有第一次投掷都是正面。
  • sheddd - 有什么问题,对于所有正面来说,它与任何其他组合的概率相同。

标签: c random


【解决方案1】:

要回答这个问题,首先我们需要看一下 rand() 代码。

来自Rand Implementation

void __cdecl srand (unsigned int seed)
{
    #ifdef _MT
        _getptd()->_holdrand = (unsigned long)seed;
    #else /* _MT */
        holdrand = (long)seed;
    #endif /* _MT */
}

int __cdecl rand (void)
{
   #ifdef _MT
    _ptiddata ptd = _getptd();
    return( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) &
    0x7fff );
   #else /* _MT */
    return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
   #endif /* _MT */
}

如您所见,随机值是根据种子值计算的(计算出的新种子值),这就是我们称这些数字为伪随机数的原因。由于我们对第一次运行很感兴趣,让我们稍微简化一下代码,让我们编写一个函数,将输入作为种子,并返回第一个 rand():

int firstRand(unsigned int seed) {
    return (((seed * 214013L + 2531011L) >> 16) & 0x7fff);
}

现在让我们用这个函数运行一个测试:

for (i = 0; i < 50; ++i) {
    printf("seed = %u; rand = %d\n", seed + i, firstRand(seed + i));
}

我得到了这个结果:

seed = 1333783311; rand = 19779
seed = 1333783312; rand = 19783
seed = 1333783313; rand = 19786
seed = 1333783314; rand = 19789
seed = 1333783315; rand = 19792
seed = 1333783316; rand = 19796
seed = 1333783317; rand = 19799
seed = 1333783318; rand = 19802
seed = 1333783319; rand = 19805
seed = 1333783320; rand = 19809
seed = 1333783321; rand = 19812
seed = 1333783322; rand = 19815
seed = 1333783323; rand = 19819
seed = 1333783324; rand = 19822
seed = 1333783325; rand = 19825
seed = 1333783326; rand = 19828
seed = 1333783327; rand = 19832
seed = 1333783328; rand = 19835
seed = 1333783329; rand = 19838
seed = 1333783330; rand = 19841
seed = 1333783331; rand = 19845
seed = 1333783332; rand = 19848
seed = 1333783333; rand = 19851
seed = 1333783334; rand = 19854
seed = 1333783335; rand = 19858
seed = 1333783336; rand = 19861
seed = 1333783337; rand = 19864
seed = 1333783338; rand = 19868
seed = 1333783339; rand = 19871
seed = 1333783340; rand = 19874
seed = 1333783341; rand = 19877
seed = 1333783342; rand = 19881
seed = 1333783343; rand = 19884
seed = 1333783344; rand = 19887
seed = 1333783345; rand = 19890
seed = 1333783346; rand = 19894
seed = 1333783347; rand = 19897
seed = 1333783348; rand = 19900
seed = 1333783349; rand = 19903
seed = 1333783350; rand = 19907
seed = 1333783351; rand = 19910
seed = 1333783352; rand = 19913
seed = 1333783353; rand = 19917
seed = 1333783354; rand = 19920
seed = 1333783355; rand = 19923
seed = 1333783356; rand = 19926
seed = 1333783357; rand = 19930
seed = 1333783358; rand = 19933
seed = 1333783359; rand = 19936
seed = 1333783360; rand = 19939

因此,如您所见,如果种子接近,则值可能会接近,并且由于您使用当前时间,因此您运行的 200 次测试的种子值都彼此接近。

time(NULL) 以秒为单位返回当前时间。为了获得更好的结果,您应该使用以毫秒为单位的时间(如果您确实需要在两次运行之间更改很多值,请对其进行一些操作)。

【讨论】:

  • 请注意,这只是rand() 的一种可能实现。 C 标准提供了一个示例实现,但并不要求使用它。
  • 如果在 Linux 或 OS X 上,使用/dev/urandom 很容易播种。
【解决方案2】:

rand 的 Windows(这里用 wine 模拟)和 glibc (x86_64) 版本完全不同,但代码将在任何地方编译。您的代码在我的 Linux 机器上运行良好,但是今天,在这个小时,您的代码的 Windows 版本在使用从时间(NULL)生成的种子时总是在第一轮为我返回 1——即使我等待了几分钟。也许几个小时、几天、几个月之后会有所不同。看看这个:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, const char *argv[]) {
    int i;
    int r;
    printf ("rand() returns:\n",RAND_MAX);
    for (i = 0; i < 25; i++) {
        srand (i);
        r = rand();
        printf ("%i ", r);
    } printf ("\nout of RAND_MAX of %li\n",RAND_MAX);
    return 0;
} 

Linux (x86_64) 上的结果:

rand() returns:
1804289383 1804289383 1505335290 1205554746 1968078301 590011675 290852541 1045618677 757547896 444454915 1215069295 1989311423 1687063760 1358590890 2146406683 762299093 462648444 1227918265 1995168598 623271449 319571911 1086411056 1857631170 1562469902 188364873 
out of RAND_MAX of 2147483647

wine 上的结果(使用 mingw 编译):

rand() returns:
38 41 45 48 51 54 58 61 64 68 71 74 77 81 84 87 90 94 97 100 103 107 110 113 116 
out of RAND_MAX of 32767

注意 windows 版本如何与种子值更紧密地耦合,因此与 32767 的 RAND_MAX 相比,它返回​​的结果非常低。

【讨论】:

    【解决方案3】:

    您的测试可能是脚本化的,并且运行速度尽可能快。

    因此大多数测试将在同一 wall time 秒内执行。

    您使用当前时间戳为伪随机数生成器播种,分辨率为一秒。

    您可以查看其他熵源,例如 Linux 或 BSD 上的 /dev/urandom/。 如果您在 x86/x64 系统上运行代码,您也可以使用 time stamp counter 作为熵源。

    【讨论】:

    • 我手动运行一次,每次运行一次......每次运行大约需要 0.3 秒。谢谢(你的)信息;我会看@你的链接!
    猜你喜欢
    • 2014-01-03
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-14
    • 2013-07-04
    相关资源
    最近更新 更多