无需 time.h 生成随机值 [英] Generating random values without time.h

查看:86
本文介绍了无需 time.h 生成随机值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在不使用 time.h 库的情况下重复生成随机数.我看到另一篇关于使用

I want to generate random numbers repeatedly without using the time.h library. I saw another post regarding use the

srand(getpid()); 

然而,这似乎对我不起作用 getpid 尚未声明.这是因为我缺少图书馆吗?如果需要,我需要弄清楚如何在不使用任何其他库的情况下随机生成数字,而不使用我目前拥有的库.

however that doesn't seem to work for me getpid hasn't been declared. Is this because I'm missing the library for it? If it is I need to work out how to randomly generate numbers without using any other libraries than the ones I currently have.

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


int main(void) {
    int minute, hour, day, month, year;
    srand(getpid());
    minute = rand() % (59 + 1 - 0) + 0;
    hour = rand() % (23 + 1 - 0) + 0;
    day = rand() % (31 + 1 - 1) + 1;
    month = rand() % (12 + 1 - 1) + 1;
    year = 2018;

    printf("Transferred successfully at %02d:%02d on %02d/%02d/%d\n", hour, 
    minute, day, month, year);

    return 0;
}

注意: 我只能使用库<stdio.h> — 赋值的严格准则.

NB: I can only use libraries <stdio.h> and <stdlib.h> and <string.h> — strict guidelines for an assignment.

推荐答案

尚未声明 getpid.

getpid hasn't been declared.

不,因为您没有在声明它的地方包含 <unistd.h> 标头(并且根据您的 评论,你不能使用它,因为你被限制使用).

No, because you haven't included the <unistd.h> header where it is declared (and according to your comment, you cannot use it, because you're restricted to using <stdlib.h>, <string.h>, and <stdio.h>).

在那种情况下,我会使用类似的东西

In that case, I would use something like

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

static int randomize_helper(FILE *in)
{
    unsigned int  seed;

    if (!in)
        return -1;

    if (fread(&seed, sizeof seed, 1, in) == 1) {
        fclose(in);
        srand(seed);
        return 0;
    }

    fclose(in);
    return -1;
}

static int randomize(void)
{
    if (!randomize_helper(fopen("/dev/urandom", "r")))
        return 0;
    if (!randomize_helper(fopen("/dev/arandom", "r")))
        return 0;
    if (!randomize_helper(fopen("/dev/random", "r")))
        return 0;

    /* Other randomness sources (binary format)? */

    /* No randomness sources found. */
    return -1;
}

和一个简单的 main() 来输出一些伪随机数:

and a simple main() to output some pseudorandom numbers:

int main(void)
{
    int i;

    if (randomize())
        fprintf(stderr, "Warning: Could not find any sources for randomness.\n");

    for (i = 0; i < 10; i++)
        printf("%d\n", rand());

    return EXIT_SUCCESS;
}

/dev/urandom/dev/random 字符设备可用于 Linux、FreeBSD、macOS、iOS、Solaris、NetBSD、Tru64 Unix 5.1B、AIX5.2、HP-UX 11i v2、/dev/random/dev/arandom 在 OpenBSD 5.1 及更高版本上.

The /dev/urandom and /dev/random character devices are available in Linux, FreeBSD, macOS, iOS, Solaris, NetBSD, Tru64 Unix 5.1B, AIX 5.2, HP-UX 11i v2, and /dev/random and /dev/arandom on OpenBSD 5.1 and later.

像往常一样,Windows 似乎没有提供任何此类随机源:Windows C 程序必须改用专有的 Microsoft 接口.

As usual, it looks like Windows does not provide any such randomness sources: Windows C programs must use proprietary Microsoft interfaces instead.

randomize_helper() 如果输入流为 NULL,或者无法从中读取 unsigned int ,则返回非零值.如果它可以从中读取一个 unsigned int,它用于为您可以使用 rand() 访问的标准伪随机数生成器做种子(它返回一个介于 0 和 int 之间的int代码>RAND_MAX,包括).在所有情况下,randomize_helper() 关闭非 NULL 流.

The randomize_helper() returns nonzero if the input stream is NULL, or if it cannot read an unsigned int from it. If it can read an unsigned int from it, it is used to seed the standard pseudorandom number generator you can access using rand() (which returns an int between 0 and RAND_MAX, inclusive). In all cases, randomize_helper() closes non-NULL streams.

您可以轻松地将其他二进制随机源添加到 randomize().

You can add other binary randomness sources to randomize() trivially.

如果 randomize() 返回 0,rand() 应该返回伪随机数.否则,rand() 将返回相同的默认伪随机数序列.(它们仍然是随机的",但每次运行程序时都会出现相同的序列.如果randomize()返回0,则每次运行程序时序列都会不同.)

If randomize() returns 0, rand() should return pseudorandom numbers. Otherwise, rand() will return the same default sequence of pseudorandom numbers. (They will still be "random", but the same sequence will occur every time you run the program. If randomize() returns 0, the sequence will be different every time you run the program.)

大多数标准 C rand() 实现是线性同余伪随机数生成器,通常参数选择不当,因此速度较慢,而且不是很随机".

Most standard C rand() implementations are linear congruental pseudorandom number generators, often with poor choices of parameters, and as a result, are slowish, and not very "random".

对于非加密工作,我喜欢实现 Xorshift 系列函数之一,最初由乔治·马尔萨利亚 (George Marsaglia) 撰写.它们非常非常快,而且相当随机;他们通过了大多数统计随机性测试,例如 死硬测试.

For non-cryptographic work, I like to implement one of the Xorshift family of functions, originally by George Marsaglia. They are very, very fast, and reasonably random; they pass most of the statistical randomness tests like the diehard tests.

在 OP 的情况下,可以使用 xorwow 生成器.根据当前的 C 标准,unsigned int 至少是 32 位,因此我们可以将其用作生成器类型.让我们看看实现一个来替换标准的 srand()/rand() 会是什么样子:

In OP's case, the xorwow generator could be used. According to current C standards, unsigned int is at least 32 bits, so we can use that as the generator type. Let's see what implementing one to replace the standard srand()/rand() would look like:

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

/* The Xorwow PRNG state. This must not be initialized to all zeros. */
static unsigned int  prng_state[5] = { 1, 2, 3, 4, 5 };

/* The Xorwow is a 32-bit linear-feedback shift generator. */
#define  PRNG_MAX  4294967295u

unsigned int  prng(void)
{
    unsigned int  s, t;

    t = prng_state[3] & PRNG_MAX;
    t ^= t >> 2;
    t ^= t << 1;
    prng_state[3] = prng_state[2];
    prng_state[2] = prng_state[1];
    prng_state[1] = prng_state[0];
    s = prng_state[0] & PRNG_MAX;
    t ^= s;
    t ^= (s << 4) & PRNG_MAX;
    prng_state[0] = t;
    prng_state[4] = (prng_state[4] + 362437) & PRNG_MAX;
    return (t + prng_state[4]) & PRNG_MAX;
}

static int prng_randomize_from(FILE *in)
{
    size_t        have = 0, n;
    unsigned int  seed[5] = { 0, 0, 0, 0, 0 };

    if (!in)
        return -1;

    while (have < 5) {
        n = fread(seed + have, sizeof seed[0], 5 - have, in);
        if (n > 0 && ((seed[0] | seed[1] | seed[2] | seed[3] | seed[4]) & PRNG_MAX) != 0) {
            have += n;
        } else {
            fclose(in);
            return -1;
        }
    }

    fclose(in);
    prng_seed[0] = seed[0] & PRNG_MAX;
    prng_seed[1] = seed[1] & PRNG_MAX;
    prng_seed[2] = seed[2] & PRNG_MAX;
    prng_seed[3] = seed[3] & PRNG_MAX;
    prng_seed[4] = seed[4] & PRNG_MAX;

    /* Note: We might wish to "churn" the pseudorandom
             number generator state, to call prng()
             a few hundred or thousand times. For example:
       for (n = 0; n < 1000; n++) prng();
             This way, even if the seed has clear structure,
             for example only some low bits set, we start
             with a PRNG state with set and clear bits well
             distributed.
    */

    return 0;
}

int prng_randomize(void)
{
    if (!prng_randomize_from(fopen("/dev/urandom", "r")))
        return 0;
    if (!prng_randomize_from(fopen("/dev/arandom", "r")))
        return 0;
    if (!prng_randomize_from(fopen("/dev/random", "r")))
        return 0;
    /* Other sources? */
    /* No randomness sources found. */
    return -1;
}

上面对应的main()

int main(void)
{
    int  i;

    if (prng_randomize())
        fprintf(stderr, "Warning: No randomness sources found!\n");

    for (i = 0; i < 10; i++)
        printf("%u\n", prng());

    return EXIT_SUCCESS;
}

请注意,PRNG_MAX 有双重用途.一方面,它告诉 prng() 可以返回的最大值——它是一个 unsigned int,而不是像 rand() 那样的 int.另一方面,因为必须是 232-1 = 4294967295,所以我们也用它来保证序列中生成下一个伪随机数时的临时结果保持 32 位.如果在 stdint.hinttypes.h 中声明的 uint32_t 类型可用,我们可以使用它并删除掩码(& PRNG_MAX).

Note that PRNG_MAX has a dual purpose. On one hand, it tells the maximum value prng() can return -- which is an unsigned int, not int like rand(). On the other hand, because it must be 232-1 = 4294967295, we also use it to ensure the temporary results when generating the next pseudorandom number in the sequence remain 32-bit. If the uint32_t type, declared in stdint.h or inttypes.h were available, we could use that and drop the masks (& PRNG_MAX).

请注意,prng_randomize_from() 函数的编写使其仍然有效,即使随机源无法一次提供所有请求的字节,并返回一个短计数".这是否会在实践中发生还有待商榷,但我更愿意确定.另请注意,它不接受全为零的状态,因为这是 Xorwow PRNG 的单个禁止初始种子状态.

Note that the prng_randomize_from() function is written so that it still works, even if the randomness source cannot provide all requested bytes at once, and returns a "short count". Whether this occurs in practice is up to debate, but I prefer to be certain. Also note that it does not accept the state if it is all zeros, as that is the one single prohibited initial seed state for the Xorwow PRNG.

你显然可以同时使用 srand()/rand()prng()/prng_randomize()> 在同一个程序中.我写它们是为了让 Xorwow 生成器函数都以 prng 开头.

You can obviously use both srand()/rand() and prng()/prng_randomize() in the same program. I wrote them so that the Xorwow generator functions all start with prng.

通常,我会将 PRNG 实现放入一个头文件中,这样我就可以通过编写一个很小的测试程序来轻松地测试它(以验证它是否有效);但也让我可以通过切换到另一个头文件来切换 PRNG 实现.(在某些情况下,我将 PRNG 状态放入一个结构中,并让调用者提供一个指向该状态的指针,以便可以同时使用任意数量的 PRNG,彼此独立.)

Usually, I do put the PRNG implementation into a header file, so that I can easily test it (to verify it works) by writing a tiny test program; but also so that I can switch the PRNG implementation simply by switching to another header file. (In some cases, I put the PRNG state into a structure, and have the caller provide a pointer to the state, so that any number of PRNGs can be used concurrently, independently of each other.)

这篇关于无需 time.h 生成随机值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆