简体   繁体   English

无需time.h即可生成随机值

[英]Generating random values without time.h

I want to generate random numbers repeatedly without using the time.h library. 我想不使用time.h库而反复生成随机数。 I saw another post regarding use the 我看到了另一则有关使用

srand(getpid()); 

however that doesn't seem to work for me getpid hasn't been declared. 但是,这似乎不适用于我getpid尚未声明。 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;
}

NB: I can only use libraries <stdio.h> and <stdlib.h> and <string.h> — strict guidelines for an assignment. 注意: 我只能使用库<stdio.h><stdlib.h><string.h> -作业的严格指导原则。

getpid hasn't been declared. 尚未声明getpid。

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> ). 不,因为您没有在声明的地方包含<unistd.h>标头(并且根据您的评论 ,您无法使用它,因为您只能使用<stdlib.h><string.h> ,和<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;
}

and a simple main() to output some pseudorandom numbers: 和一个简单的main()来输出一些伪随机数:

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;
}

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. /dev/urandom/dev/random字符设备可用于Linux,FreeBSD,macOS,iOS,Solaris,NetBSD,Tru64 Unix 5.1B,AIX 5.2,HP-UX 11i v2, /dev/random/dev/arandom在OpenBSD 5.1和更高版本上是/dev/arandom

As usual, it looks like Windows does not provide any such randomness sources: Windows C programs must use proprietary Microsoft interfaces instead. 像往常一样,Windows似乎没有提供任何此类随机性源:Windows C程序必须使用专有的Microsoft接口。

The randomize_helper() returns nonzero if the input stream is NULL, or if it cannot read an unsigned int from it. 如果输入流为NULL,或者无法从中读取unsigned int ,则randomize_helper()返回非零。 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). 如果它可以从中读取一个无符号的int,则可以使用它为可以使用rand()访问的标准伪随机数生成器生成种子(该伪随机数生成器返回一个介于0和RAND_MAX之间的int )。 In all cases, randomize_helper() closes non-NULL streams. 在所有情况下, randomize_helper()关闭非NULL流。

You can add other binary randomness sources to randomize() trivially. 您可以简单地将其他二进制随机性源添加到randomize()

If randomize() returns 0, rand() should return pseudorandom numbers. 如果randomize()返回0,则rand()应该返回伪随机数。 Otherwise, rand() will return the same default sequence of pseudorandom numbers. 否则, rand()将返回相同的默认伪随机数序列。 (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.) (它们仍然是“随机的”,但是每次运行程序时都会发生相同的顺序。如果randomize()返回0,则每次运行程序时的顺序都会不同。)


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". 大多数标准C rand()实现都是线性同余伪随机数生成器,通常具有很少的参数选择,结果是速度较慢,并且不是很“随机”。

For non-cryptographic work, I like to implement one of the Xorshift family of functions, originally by George Marsaglia. 对于非加密工作,我喜欢实现Xorshift系列功能之一,该功能最初是由George Marsaglia提供的。 They are very, very fast, and reasonably random; 它们非常非常快,并且相当随机。 they pass most of the statistical randomness tests like the diehard tests . 他们通过了大多数统计随机性检验,如顽固检验

In OP's case, the xorwow generator could be used. 在OP的情况下,可以使用xorwow生成器。 According to current C standards, unsigned int is at least 32 bits, so we can use that as the generator type. 根据当前的C标准, unsigned int至少为32位,因此我们可以将其用作生成器类型。 Let's see what implementing one to replace the standard srand()/rand() would look like: 让我们看看实现一个替代标准srand()/ rand()的方式是什么样的:

#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;
}

The corresponding main() to above would be 上面对应的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;
}

Note that PRNG_MAX has a dual purpose. 请注意, PRNG_MAX具有双重用途。 On one hand, it tells the maximum value prng() can return -- which is an unsigned int, not int like rand() . 一方面,它告诉prng()可以返回的最大值-这是一个无符号的 int,而不是像rand()这样的int。 On the other hand, because it must be 2 32 -1 = 4294967295, we also use it to ensure the temporary results when generating the next pseudorandom number in the sequence remain 32-bit. 另一方面,因为它必须为2 32 -1 = 4294967295,所以我们也使用它来确保生成序列中的下一个伪随机数时的临时结果保持32位。 If the uint32_t type, declared in stdint.h or inttypes.h were available, we could use that and drop the masks ( & PRNG_MAX ). 如果在stdint.hinttypes.h中声明的uint32_t类型可用,我们可以使用它并删除掩码( & PRNG_MAX )。

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" . 请注意,编写prng_randomize_from()函数以使其仍然有效,即使随机性源无法一次提供所有请求的字节并返回“短计数” 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. 另请注意,如果它全为零,则它不接受状态,因为这是Xorwow PRNG的一个禁止的初始种子状态。

You can obviously use both srand() / rand() and prng() / prng_randomize() in the same program. 你可以明显地使用这两个srand() / rand()prng() / prng_randomize()在同一个程序。 I wrote them so that the Xorwow generator functions all start with prng. 我写了它们,以便Xorwow生成器函数全部以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; 通常,我确实将PRNG实现放入头文件中,这样我就可以通过编写一个小的测试程序来轻松测试它(以验证它是否有效)。 but also so that I can switch the PRNG implementation simply by switching to another header file. 而且还使我可以仅通过切换到另一个头文件来切换PRNG实现。 (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.) (在某些情况下,我将PRNG状态放入一个结构中,并要求调用者提供指向该状态的指针,以便可以相互独立地同时使用任意数量的PRNG。)

however that doesn't seem to work for me getpid hasn't been declared. 但是,这似乎不适用于我getpid尚未声明。

That's because you need to include the headers for getpid() : 那是因为您需要包括getpid()的标头:

   #include <sys/types.h>
   #include <unistd.h>

Another option is to use time() to seed (instead of getpid() ): 另一种选择是使用time()进行播种(而不是getpid() ):

   srand((unsigned int)time(NULL));

As other answer pointed, you need to include the unistd.h header. 正如其他答案指出的那样,您需要包括unistd.h标头。 If you don't want to do that then put the declaration of getpid() above main() . 如果您不想这样做,则将getpid()的声明放在main()之上。 Read the manual page of getpid() here http://man7.org/linux/man-pages/man2/getpid.2.html http://man7.org/linux/man-pages/man2/getpid.2.html上阅读getpid()的手册页。

One approach may be 一种方法可能是

#include <stdio.h>
#include <stdlib.h>
pid_t getpid(void); /* put the declrataion of getpid(), if don't want to include the header */
int main(void) {

   /* .. some code .. */
   return 0;
} 

Or you can use time() like 或者你可以像这样使用time()

srand((unsigned int)time(NULL));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM