C中的长随机数

时间:2016-06-11 06:44:04

标签: c random numbers int long-integer

我的问题非常简单(愚蠢,也许)。 我需要一个使用C语言的长随机数尽可能简单。我研究了整个互联网,并没有找到任何可以帮助我的东西。我唯一能找到的是rand()函数无法处理大于32,767的数字。

这是我的代码的一部分,长号应该在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();
}

3 个答案:

答案 0 :(得分:3)

您可以通过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;
}

应该注意的是,这种方法会有偏差(即所有数字都不具有相同的概率),并且绝对不是加密安全。如果你想要,你根本不应该使用rand()

以下是测试所有数字至少可能的主要功能:

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

答案 1 :(得分:1)

我假设你想要一个范围为[0,1000000 [范围长度为10 6 的随机数。

与在[0,1000 [,一个用于高阶(十进制)数字,一个用于低阶数字)中选取两个随机数完全相同。但是在这个范围内工作要容易得多......

如果你想要一个正确的随机生成,你应该担心每个可能的数字的概率,并尽量保持它相等。因此,您必须先搜索低于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;
}

然后您可以使用

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

当你在[0,1000 [,比如n1n2范围内有两个随机数时,只需执行以下操作:

n = period * n1 + n2;

当然,上面假设你有一个正确的rand函数。如果不确定在我的系统上使用random - rand手册页,则表明它使用与random相同的算法,这就是为什么我认为我可以安全地使用它,但它也说:

  

然而,在较旧的rand()实现以及不同系统上的当前实现中,低阶位比高阶位更不随机。当需要良好的随机性时,请勿在可移植的应用程序中使用此功能。 (改为使用随机(3)。)

答案 2 :(得分:-1)

一个糟糕但有效的解决方案是将rand()的结果乘以MAX / RAND_MAX(我相信这有一个常数,如果没有,32767)。

我仍然认为应该有更大数字的兰特。

编辑:需要将分区强制转换为浮动(或双重),然后再转换为长整数。