使用setstate(3)不会产生预期的随机数序列

时间:2014-02-26 00:20:27

标签: c random

对于多人游戏,我需要在所有参与设备上生成相同的随机数序列。显然,这是通过在所有设备上使用相同的种子来实现的。当random()被调用到应该在所有设备上产生相同序列的例程之外时会出现问题。因此,在此例程中,我尝试使用setstate来保留状态数组。据我了解man random(3),在此例程之外调用random()则不应更改序列。

但是,以下代码不会为Run 1和2生成相同的输出:

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

int main(int argc, const char * argv[])
{

    char state[256];

    printf("Run 1 : ");
    initstate(123, state, 256);
    for (int i=1; i < 10; i++) {
        printf("%ld ", random());
    }

    printf("\nRun 2 : ");
    initstate(123, state, 256);
    for (int i=1; i < 10; i++) {
                setstate(state); // load preserved state
                printf("%ld ", random());
                *state = *setstate(state); // preserve state 
                random(); // this simulates a call to random() from outside
        }
        printf("\n");
        return 0;
}


Run 1 : 1597493280 1407130876 1753502901 1965067074 377602131 83146350 274392949 1718024305 1016176754 
Run 2 : 1597493280 537479855 1611694138 941096776 83164437 1459338036 1256894804 1618690717 1091902527 
Program ended with exit code: 0

有谁知道为什么? 或者可能有另一种方法可以达到预期的效果?

记录:使用Xcode 5在OS X和iOS上运行。

修改 在Arkku和minitech的帮助下,以下更改使Run 2的输出与Run 1相同:

    printf("\nRun 2 : ");
char otherstate[256];
initstate(123, state, 256);
for (int i=1; i < 10; i++) {
    // preserve whatever state is currently active
    // and set the current state to "my" state
    memcpy(otherstate, setstate(state), 256);
    printf("%ld ", random());
    // switch back to the other state
    memcpy(state, setstate(otherstate), 256);
    // now this call does not affect the sequence that get's printf'd
    random();
}
printf("\n");

2 个答案:

答案 0 :(得分:1)

在第二个循环中,您调用random()而不打印该值。此外,setstate行无用;每次使用相同的数组(state),因此状态将不断变化。这两个序列完全相同:

for (int i = 1; i <= 2; ++i) {
   printf("\nRun %d: ", i);
   initstate(123, state, sizeof(state));
   for (int i=1; i < 10; i++) {
       printf("%ld ", random());
   }
}

如果您需要在生成一些随机数后保存状态,然后再返回到相同的状态,则必须在不同的状态数组之间交替,例如:

char state[256], state2[256];
initstate(123, state, sizeof(state));
char *saved = initstate(123, state2, sizeof(state2));
for (int i=1; i < 10; i++) {
    saved = setstate(saved);
    printf("%ld ", random());
    saved = setstate(saved);
    (void) random();
    (void) random();
}

initstatesetstate的每次调用都会返回指向之前状态数组的指针。要返回到该状态,您需要将setstate作为参数调用,并将返回的指针存储在某处(可能指向相同的指针,如此处所示)。您还需要有两个不同的状态数组,或者只是反复设置相同的数组 - 在上面的示例中,saved的初始值来自对 second 的调用{ {1}},即它是第一次调用中设置的状态数组。 (第一次调用可能会返回一些内部数组,但是对于与所需数组大小一致的结果,我认为最好自己创建两个数组。)

答案 1 :(得分:1)

  • *state = *setstate(state);
    仅复制州的第一个字节

  • 随机数生成器实际上每次都在更改状态数组

保持原始阵列的便利。

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

int main(int argc, const char * argv[])
{

    char state[256];
    char* oldstate;

    printf("Run 1 : ");
    oldstate = initstate(123, state, 256);
    for (int i=1; i < 10; i++) {
        printf("%ld ", random());
    }
    setstate(oldstate);

    printf("\nRun 2 : ");
    initstate(123, state, 256);
    setstate(oldstate);
    for (int i=1; i < 10; i++) {
        setstate(state); // load preserved state
        printf("%ld ", random());
        setstate(oldstate);
        random(); // this simulates a call to random() from outside
    }
    printf("\n");
    return 0;
}

哦,我根本不会这样做。制作自己的RNG并让它接受状态作为参数。