我需要使用C生成随机64位无符号整数。我的意思是,范围应该是0
到18446744073709551615
。 RAND_MAX
为1073741823
。
我在链接中找到了一些可能重复的解决方案,但答案主要是连接一些rand()
结果或进行一些增量算术运算。所以结果总是18位或20位。我还想要5
,11
,33387
等结果,而不只是3771778641802345472
。
顺便说一句,我对C的确没有太多经验,但任何方法,代码示例和想法都可能是有益的。
答案 0 :(得分:4)
如果您不需要加密安全的伪随机数,我建议您使用MT19937-64。它是Mersenne Twister PRNG的64位版本。
请不要将rand()
输出结合起来,也不要建立其他技巧。使用现有的实施:
答案 1 :(得分:3)
关于"因此结果总是18位数或20位数。"
见@Thomas comment。如果您生成足够长的随机数,代码将创建5,11和33387之类的代码。如果代码生成1,000,000,000个数字/秒,则可能需要一年的时间,因为非常小的数字<在所有64位数字中,100,000是如此罕见。
rand()
simple返回随机位。一种简单的方法一次拉1位
uint64_t rand_uint64_slow(void) {
uint64_t r = 0;
for (int i=0; i<64; i++) {
r = r*2 + rand()%2;
}
return r;
}
假设RAND_MAX
是2的1的幂,如在OP的情况1073741823 == 0x3FFFFFFF
中那样,利用每次生成30位的优势。以下代码将调用rand()
3次 - 有点浪费。相反,移出的位可以保存为下一个随机数,但这会带来其他问题。把它留了一天。
uint64_t rand_uint64(void) {
uint64_t r = 0;
for (int i=0; i<64; i += 30) {
r = r*((uint64_t)RAND_MAX + 1) + rand();
}
return r;
}
便携式循环计数方法避免了30
#if RAND_MAX/256 >= 0xFFFFFFFFFFFFFF
#define LOOP_COUNT 1
#elif RAND_MAX/256 >= 0xFFFFFF
#define LOOP_COUNT 2
#elif RAND_MAX/256 >= 0x3FFFF
#define LOOP_COUNT 3
#elif RAND_MAX/256 >= 0x1FF
#define LOOP_COUNT 4
#else
#define LOOP_COUNT 5
#endif
uint64_t rand_uint64(void) {
uint64_t r = 0;
for (int i=LOOP_COUNT; i > 0; i--) {
r = r*(RAND_MAX + (uint64_t)1) + rand();
}
return r;
}
评论here的自相关效应是由弱rand()
引起的。 C没有指定随机数生成的特定方法。以上依赖rand()
- 或任何基本随机函数 - 是好的。
如果rand()
低于标准,则代码应使用其他生成器。然而,人们仍然可以使用这种方法来建立更大的随机数。
答案 2 :(得分:1)
如果你有足够好的随机字节源(例如,linux机器上的/ dev / random或/ dev / urandom),你可以简单地从该源消耗8个字节并连接它们。如果它们是独立的并且具有线性分布,那么您可以设置。
如果你不这样做,你可以通过做同样的事情来逃避,但你的伪随机生成器中可能会有一些人工制品给各种各样的hi-jinx提供了一个脚趾。
示例代码假设我们有一个开放的二进制文件FILE *source
:
/* Implementation #1, slightly more elegant than looping yourself */
uint64_t 64bitrandom()
{
uint64_t rv;
size_t count;
do {
count = fread(&rv, sizeof(rv), 1, source);
} while (count != 1);
return rv;
}
/* Implementation #2 */
uint64_t 64bitrandom()
{
uint64_t rv = 0;
int c;
for (i=0; i < sizeof(rv); i++) {
do {
c = fgetc(source)
} while (c < 0);
rv = (rv << 8) | (c & 0xff);
}
return rv;
}
如果你替换&#34;从随机设备读取随机字节&#34;使用&#34;从函数调用中获取字节&#34;,您所要做的就是调整方法#2中的移位。
你更有可能得到一个数字很多的数字&#34;与#34;少量数字&#34; (在0到2之间的所有数字** 64,大约95%有十九位或更多十进制数字,所以这就是你最常得到的。
答案 3 :(得分:0)
如果您有32或16位随机值 - 生成2或4个随机数,并将它们与<<
和|
合并为一个64位。
uint64_t rand_uint64(void) {
// Assuming RAND_MAX is 2^31.
uint64_t r = rand();
r = r<<30 | rand();
r = r<<30 | rand();
return r;
}
答案 4 :(得分:0)
我尝试过这段代码here,似乎在那里工作正常。
#include <time.h>
#include <stdlib.h>
#include <math.h>
int main(){
srand(time(NULL));
int a = rand();
int b = rand();
int c = rand();
int d = rand();
long e = (long)a*b;
e = abs(e);
long f = (long)c*d;
f = abs(f);
long long answer = (long long)e*f;
printf("value %lld",answer);
return 0;
}
我运行了几次迭代,得到以下输出:
值1869044101095834648
值2104046041914393000
值1587782446298476296
值604955295827516250
值41152208336759610
值57792837533816000
答案 5 :(得分:0)
如果你不介意重复的伪随机序列(嘿,64位你不会注意到你一生中的重复;)你可以处理一个小于你要求的范围的值(0 isn'即将发生),LCG或MCG是一个非常简单的解决方案。 Wikipedia: Linear congruential generator转到here生成几个素数,并使用一个用于模数,另一个用于下面的乘数。 (警告:这个序列是可猜测的,因此它不安全)
#include <stdio.h>
#include <stdint.h>
uint64_t
mcg64(void)
{
static uint64_t i = 1;
return (i = (164603309694725029ull * i) % 14738995463583502973ull);
}
int
main(int ac, char * av[])
{
for (int i = 0; i < 10; i++)
printf("%016p\n", mcg64());
}
答案 6 :(得分:-1)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
unsigned long long int randomize(unsigned long long int uint_64);
int main(void)
{
srand(time(0));
unsigned long long int random_number = randomize(18446744073709551615);
printf("%llu\n",random_number);
random_number = randomize(123);
printf("%llu\n",random_number);
return 0;
}
unsigned long long int randomize(unsigned long long int uint_64)
{
char buffer[100] , data[100] , tmp[2];
//convert llu to string,store in buffer
sprintf(buffer, "%llu", uint_64);
//store buffer length
size_t len = strlen(buffer);
//x : store converted char to int, rand_num : random number , index of data array
int x , rand_num , index = 0;
//condition that prevents the program from generating number that is bigger input value
bool Condition = 0;
//iterate over buffer array
for( int n = 0 ; n < len ; n++ )
{
//store the first character of buffer
tmp[0] = buffer[n];
tmp[1] = '\0';
//convert it to integer,store in x
x = atoi(tmp);
if( n == 0 )
{
//if first iteration,rand_num must be less than or equal to x
rand_num = rand() % ( x + 1 );
//if generated random number does not equal to x,condition is true
if( rand_num != x )
Condition = 1;
//convert character that corrosponds to integer to integer and store it in data array;increment index
data[index] = rand_num + '0';
index++;
}
//if not first iteration,do the following
else
{
if( Condition )
{
rand_num = rand() % ( 10 );
data[index] = rand_num + '0';
index++;
}
else
{
rand_num = rand() % ( x + 1 );
if( rand_num != x )
Condition = 1;
data[index] = rand_num + '0';
index++;
}
}
}
data[index] = '\0';
char *ptr ;
//convert the data array to unsigned long long int
unsigned long long int ret = _strtoui64(data,&ptr,10);
return ret;
}