c初学者兰特()

时间:2012-04-07 06:53:30

标签: c random

此代码连续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;
}

3 个答案:

答案 0 :(得分:4)

要回答这个问题,首先我们需要查看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)以秒为单位返回当前时间。为了获得更好的结果,您应该以毫秒为单位使用时间(如果您真的需要在两次运行之间更改一些值,请对其进行一些操作)。

答案 1 :(得分:3)

Windows(这里用wine模拟)和glibc(x86_64)版本的rand完全不同,但代码将编译到任何一个地方。你的代码在我的Linux机器上运行得很好,但今天,在这个时候,当使用从时间生成的种子(NULL)时,Windows代码总是在第一次滚动时为我返回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

葡萄酒的结果(用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版本如何更紧密地耦合到种子值,因此与RAND_MAX 32767相比,它返回​​的结果非常低。

答案 2 :(得分:1)

可能你的测试编写脚本并运行得和你运行它们一样快。

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

使用当前时间戳为伪随机数生成器设定种子,该时间戳的分辨率为1秒。

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