我的问题非常简单(愚蠢,也许)。 我需要一个使用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();
}
答案 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 [,比如n1
和n2
范围内有两个随机数时,只需执行以下操作:
n = period * n1 + n2;
当然,上面假设你有一个正确的rand
函数。如果不确定在我的系统上使用random
- rand
手册页,则表明它使用与random
相同的算法,这就是为什么我认为我可以安全地使用它,但它也说:
然而,在较旧的rand()实现以及不同系统上的当前实现中,低阶位比高阶位更不随机。当需要良好的随机性时,请勿在可移植的应用程序中使用此功能。 (改为使用随机(3)。)
答案 2 :(得分:-1)
一个糟糕但有效的解决方案是将rand()的结果乘以MAX / RAND_MAX(我相信这有一个常数,如果没有,32767)。
我仍然认为应该有更大数字的兰特。
编辑:需要将分区强制转换为浮动(或双重),然后再转换为长整数。