C语言 “srand(time(0)* int_value))”是一种为每次执行获取不同值的好方法吗?

ljo96ir5  于 2023-11-16  发布在  其他
关注(0)|答案(5)|浏览(139)

我想在每次执行时得到0到10之间的随机浮点值,如果我不使用**srand(time(0)),**我的随机值在每次执行时总是相同的。然而,如果我使用这个,我得到不同的值,但它在两次连续执行之间的变化是0.01。
所以我的问题是:
如果我使用srand(time(0) * 1000),我每次执行都会得到不同的随机数。这是一种正确的使用方式吗?或者会因为种子限制或特定时间的类似情况而溢出?
这里有一个简单的函数来获取0到10之间的不同浮点值

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

int main() {

    srand(time(0) * 1000);

    int i;
    for (i = 0; i < 10; i++) {
        float randomValue = ((float)rand() / RAND_MAX) * 10;
        printf("Random float value %d: %.2f\n", i + 1, randomValue);
    }

    return 0;
}

字符串

um6iljoc

um6iljoc1#

如果我使用srand(time(0)* 1000),我每次执行都会得到不同的随机数。这样使用是正确的吗?或者会因为种子限制或特定时间的类似原因而溢出?
srand(time(0) * 1000)srand(time(0))弱,原因如下。
time() typical返回一个整数。按1000缩放(与53 * 23相同)的结果是3个最低有效位为0的乘积。将该乘积转换为unsignedvoid srand(unsigned int seed);参数的类型保留这3个最低有效位为0。unsigned seed及其n位(通常为32)现在具有少3的“随机”位。
prime > 2而不是1000缩放可能有好处。
“srand(time(0)* int_value))”是一种为每次执行获取不同值的好方法吗?
一种常见的替代方法是使用srand()进行初始化,使得在同一time()(例如,同一秒)中启动的两个程序可能具有不同的种子,这种方法涉及使用其他“随机”源。
无论使用什么源,最好使用 unsigned math而不是|, &, *, /, ...^它们。
一些系统提供进程ID。

#include <unistd.h>

...
pid_t pid = getpid();
// `time_t` may be a floating point type.  Convert to an integer to allow `^`
unsigned long long t = (unsigned long long) time(0);
srand(t ^ pid);

字符串
如果真正的用户输入发生在srand()之前,另一个有用的来源是查询clock()
@selbie提供了一个获取变量地址的有用想法。该地址可以是固定的,也可以在每次程序运行时都不同。将其排它或-不会造成任何伤害,但可能会提供更多的“随机”位。

  • 更深:当将各种“随机”位混合在一起时,请考虑将随机位分散开来。时间位往往具有公共的MS位和不同的LS位。时间和PID往往都递增。时钟往往具有比LS位高出几位的最不同的位。有关C++方法,请参阅Recommended way to initialize srand?。它与C有一定的相关性。

当然,各种系统提供比srand(), rand()更好的上级随机数功能。

3j86kqsm

3j86kqsm2#

如果您没有安全问题,timerand作为随机数种子是完全合适的。请注意:

  • time返回一个以秒为单位的值。因此,如果你的程序在同一秒内被启动多次,它将使用相同的种子,因此,生成相同的结果。
  • 在你的例子中,将time(0)乘以1000没有意义。只是时间(0)或time(NULL)

这里有一些我很久以前写的随机数生成器的种子代码。它不一定是安全的或最好的。但它适用于Windows,Linux和Mac。

uint32_t entropy=0;

    // on x86, the rdtsc instruction is about as good as it gets for a random sequence number
    // on linux, there's /dev/urandom

#ifdef _WIN32
    // on windows, there's lots of simple stuff we can get at to give us a random number
    // the rdtsc instruction is about as good as it gets
    uint64_t clock = __rdtsc();
    entropy ^= (uint32_t)(clock);
#else
    // on linux, /dev/urandom should be sufficient
    {
        int randomfile = ::open("/dev/urandom", O_RDONLY);
        if (randomfile >= 0)
        {
            int readret = read(randomfile, &entropy, sizeof(entropy));
            close(randomfile);
        }
    }

    // fallback on unix when /dev/urandom isn't available
    if (entropy == 0)
    {
        entropy ^= getpid();
        entropy ^= reinterpret_cast<uintptr_t>(this); // FOR C code use the address of any local variable
        entropy ^= time(NULL);
    }

#endif

    srand(entropy);

字符串

ajsxfq5m

ajsxfq5m3#

与一个固定的数字相乘并不会使种子更随机。如果你在大约相同的时间启动两个程序,你仍然会得到相同的种子。
你可以使用一个可能具有更高分辨率的时钟来降低获得相同种子的风险:

unsigned get_seed(void) {
    struct timespec ts;
    timespec_get(&ts, TIME_UTC);
    unsigned seed = (unsigned)(ts.tv_sec * 1000000000ull + ts.tv_nsec);
    // mix in other sources of semi-randomness into seed if needed
    return seed;
}

srand(get_seed());

字符串
或者使用一个真正的随机源来播种你的PRNG,在Linux上你有/dev/random或者更新的getrandom(),你可以从中读取sizeof(unsigned)字节来创建你的种子。

lrpiutwd

lrpiutwd4#

您可以在PRNG种子中引入用户响应时间。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
    
int main(void) {
    printf("Press Enter to begin\n");
    getchar();
    
    unsigned seed = (unsigned)time(NULL) + (unsigned)clock();
    printf("seed = %u\n", seed);
    srand(seed);
    printf("rand=%u\n", rand());
    return 0;
}

字符串
如果有用户交互,也可以使用clock()修改rand()的值。

t40tm48m

t40tm48m5#

srand/rand被认为是一个糟糕的随机数生成器。无论问题是什么,主要是因为第一个生成的值与种子耦合太紧密。看看这些第一个随机值(time(0),rand,RAND_MAX,计算的浮点数):

1698920210 809398958 2147483647 0.376906
1698920242 809936782 2147483647 0.377156
1698920258 810205694 2147483647 0.377281

字符串
差值小于您的预期。一个小的解决方法是(例如)只获取一些较低有效位:

srand(time(0));

int i;
for (i = 0; i < 10; i++) {
    int r = rand()%10000;
    float randomValue = ((float)r / 10000) * 10;
    printf("Random float value %d: %.2f\n", i + 1, randomValue);
}


然后,您将得到类似于:

Random float value 1: 1.62
Random float value 2: 1.93
Random float value 3: 9.02
Random float value 4: 2.82
Random float value 5: 5.38
Random float value 6: 8.86
Random float value 7: 0.76
Random float value 8: 8.42
Random float value 9: 2.24
Random float value 10: 8.71


然后

Random float value 1: 0.29
Random float value 2: 3.16
Random float value 3: 6.03
Random float value 4: 9.83
Random float value 5: 1.78
Random float value 6: 8.02
Random float value 7: 3.79
Random float value 8: 6.96
Random float value 9: 8.49
Random float value 10: 4.01

相关问题