简体   繁体   English

C中的长随机数

[英]Long random numbers in C

My problem is really simple (silly, maybe).我的问题真的很简单(也许很愚蠢)。 I need a long random number using the C language as simple as possible.我需要一个尽可能简单的使用 C 语言的长随机数。 I researched through out the inte.net and coudn't find anything that could help me.我通过 inte.net 进行了研究,但找不到任何可以帮助我的东西。 The only thing I could find was that the rand() function cannot handle numbers bigger than 32,767.我唯一能找到的是 rand() function 无法处理大于 32,767 的数字。

Here is part of my code, and the long number should be between 0 and 1,000,000:这是我的代码的一部分,长数字应该在 0 到 1,000,000 之间:

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

#define MAX 999999

void main()
{
    int i;

    printf("\n Just a test with random numbers.");

    printf("\n ------------------------------------\n\n");

    srand(time(NULL));

    for(i = 0; i < 50; i++)
    {
        printf(" %li\n", rand() % MAX+1);
    }

    printf("\n ====================================\n");
    getch();
}

You can build bigger numbers by OR:ing together several calls to rand(). 您可以通过OR:将rand()的多个调用组合在一起来建立更大的数字。

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

#define LIMIT (1000000)

static uint16_t highest_bit(uint64_t v) {
    uint16_t out = 0;
    while (v > 0) {
        v >>= 1;
        ++out;
    }
    return out;
}

uint32_t myrand() {
    static bool init = 0;
    static uint16_t n;
    static uint16_t shift;
    if (!init) {
        uint16_t randbits = highest_bit(RAND_MAX + (uint64_t)1L);
        uint16_t outbits = highest_bit(LIMIT);
        n = (outbits + randbits - 1)/randbits;
        shift = randbits;
        init = 1;
    }
    uint32_t out = 0;
    for (uint16_t i=0; i<n; ++i) {
        out |= rand() << (i*shift);
    }
    return out % LIMIT;
}

It should be noted that this method will be biased (ie all numbers won't have the same probability), and it is definitely not cryptographically secure . 应该注意的是,这种方法将是有偏见的(即所有数字都不会具有相同的概率),并且绝对不是加密安全的 If you want that, you shouldn't be using rand() at all. 如果您愿意,则根本不应该使用rand()

Here's a little main function to test that all numbers are at least possible to get: 这是一个主要功能,用于测试所有数字至少都可以获取:

int main() {
    bool* seen = calloc(LIMIT, sizeof(bool));
    if (!seen) {
        fprintf(stderr, "failed to malloc 'seen' array\n");
        return 1;
    }
    uint32_t nseen = 0;
    uint32_t ntries = 0;
    // this could take a long time -- you can use Ctrl-C to abort a command-line program
    while (nseen < LIMIT) {
        if ((ntries & 0xffff) == 0) {
            printf("after %u tries, we've seen %u different numbers.\n", ntries, nseen);
        }
        ++ntries;
        uint32_t r = myrand();
        if (!seen[r]) {
            seen[r] = true;
            ++nseen;
        }
    }
    printf("Found them all after %u tries!\n", ntries);
    return 0;
}

I assume that you want a random number in range [0, 1000000[ that is in a range length of 10 6 . 我假设您想要一个[0,1000000 [范围为10 6的范围内的随机数。

It is exactly the same as picking two random numbers in range [0, 1000[, one for the high order (decimal) digits, one for the low order ones. 它与选择[0,1000 []范围内的两个随机数完全相同,一个随机数用于高阶(十进制)数字,一个随机数用于低阶数字。 But it is much easier to work in that range... 但是在该范围内工作要容易得多...

If you want a correct random generation, you should worry for the probability of every possible number and try to keep it as equal as possible. 如果想要正确的随机数生成,则应担心每个可能数的概率,并尝试使其尽可能相等。 So you must first search the greatest power of 1000 below RAND_MAX, reject all number greater than it and take the modulus 1000 of each kept value. 因此,您必须首先在RAND_MAX以下搜索最大幂1000,拒绝大于它的所有数字,并取每个保留值的模数1000。

// Find the max number to keep
int period = 1000
unsigned int max = period;
while (max < (unsigned long) RAND_MAX) {
    unsigned long t = max * period;
    if (t < max) break;  // test for a possible overflow
    max = t;
}

You can then use 然后,您可以使用

for(;;) {
    unsigned long randnum = rand();
    if (randnum < max) {
        randnum %= period;
        break;
    }
}

And when you have two random number in range [0, 1000[, say n1 and n2 , just do: 当您有两个随机数[[0,1000 [,比如n1n2 ,只需执行以下操作:

n = period * n1 + n2;

Of course above assume that you have a correct rand function. 当然,以上假设您具有正确的rand函数。 If unsure use random - rand man page on my system states it uses same algorythm as random that's why I assume I can use it securely, but it also says: 如果不确定使用random -我系统上的rand手册页指出它使用与random相同的算法,这就是为什么我认为我可以安全使用它的原因,但是它还说:

However, on older rand() implementations, and on current implementations on different systems, the lower-order bits are much less random than the higher-order bits. 但是,在较旧的rand()实现以及当前在不同系统上的实现中,低阶位的随机性远小于高阶位的随机性。 Do not use this function in applications intended to be portable when good randomness is needed. 当需要良好的随机性时,请勿在打算用于便携式应用程序中使用此功能。 (Use random(3) instead.) (改为使用random(3)。)

Cryptographical safe long number generator:加密安全长数生成器:

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

unsigned long xorshift(unsigned long state[static 1]) {
    unsigned long x = state[0];
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    state[0] = x;
    return x;
}

long random_long(long min, long max) {
    int urandom = open("/dev/urandom", O_RDONLY);
    unsigned long state[1];
    read(urandom, state, sizeof(state));
    close(urandom);
    unsigned long range = (unsigned long) max - min + 1;
    unsigned long random_value = xorshift(state) % range;
    return (long) (random_value + min);
}

long* random_long_array(long min, long max, int n) {
    long *numbers = (long*) malloc(n * sizeof(long));
    for (int i = 0; i < n; i++) {
        numbers[i] = random_long(min, max);
    }
    return numbers;
}

int main() {
    //FOR TESTING
    long min = 0;
    long max = 5000000;
    int n = 100;
    long *numbers = random_long_array(min, max, n);

    printf("Random number between %ld and %ld:\n%ld\n", min, max, random_long(min, max));

    printf("Random numbers between %ld and %ld:\n", min, max);

    for (int i = 0; i < n; i++) {
        printf("%ld\n", numbers[i]);
    }

    free(numbers);
    return 0;
}

A bad but working solution would be to multiply the result of rand() with MAX / RAND_MAX (I believe there was a constant for this, if not, 32767). 一个不好的但可行的解决方案是将rand()的结果与MAX / RAND_MAX相乘(我相信对此有一个常数,如果不是,则为32767)。

I still think there should be a rand for the larger numbers out there though. 我仍然认为,尽管如此,应该有大量的兰特。

EDIT: Need to typecast the division to float (or double), then back to long. 编辑:需要将除法转换为浮点型(或加倍),然后再变长。

Use random() from <stdlib.h> .使用<stdlib.h>中的random()

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

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