I need generate random 64-bit unsigned integers using C. I mean, the range should be 0
to 18446744073709551615
. RAND_MAX
is 1073741823
.
我需要使用C生成随机64位无符号整数。我的意思是,范围应该是0到18446744073709551615.RAND_MAX是1073741823。
I found some solutions in the links which might be possible duplicates but the answers mostly concatenates some rand()
results or making some incremental arithmetic operations. So results are always 18 digits or 20 digits. I also want outcomes like 5
, 11
, 33387
, not just 3771778641802345472
.
我在链接中找到了一些可能重复的解决方案,但答案主要是连接一些rand()结果或进行一些增量算术运算。因此结果总是18位或20位。我也想要5,11,33387等结果,而不仅仅是3771778641802345472。
By the way, I really don't have so much experience with the C but any approach, code samples and idea could be beneficial.
顺便说一下,我真的没有这么多的C经验,但任何方法,代码样本和想法都可能是有益的。
7 个解决方案
#1
3
If you don't need cryptographically secure pseudo random numbers, I would suggest using MT19937-64. It is a 64 bit version of Mersenne Twister PRNG.
如果您不需要加密安全的伪随机数,我建议使用MT19937-64。它是Mersenne Twister PRNG的64位版本。
Please, do not combine rand()
outputs and do not build upon other tricks. Use existing implementation:
请不要组合rand()输出,也不要构建其他技巧。使用现有实施:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
#2
3
Concerning "So results are always 18 digits or 20 digits."
关于“所以结果总是18位或20位”。
See @Thomas comment. If you generate random numbers long enough, code will create ones like 5, 11 and 33387. If code generates 1,000,000,000 numbers/second, it may take a year as very small numbers < 100,000 are so rare amongst all 64-bit numbers.
请参阅@Thomas评论。如果您生成足够长的随机数,代码将创建5,11和33387之类的代码。如果代码生成1,000,000,000个数字/秒,则可能需要一年,因为非常小的数字<100,000在所有64位数字中非常罕见。
rand()
simple returns random bits. A simplistic method pulls 1 bit at a time
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;
}
Assuming RAND_MAX
is some power of 2 - 1 as in OP's case 1073741823 == 0x3FFFFFFF
, take advantage that 30 bits are generated each time. The following code will call rand()
3 times - a tad wasteful. Instead bits shifted out could be saved for the next random number, but that brings in other issues. Leave that for another day.
假设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;
}
A portable loop count method avoids the 30
便携式循环计数方法避免了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;
}
The autocorrelation effects commented here are caused by a weak rand()
. C does not specify a particular method of random number generation. The above relies on rand()
- or whatever base random function employed - being good.
这里评论的自相关效应是由弱rand()引起的。 C没有指定随机数生成的特定方法。上面依赖于rand() - 或任何基本随机函数 - 是好的。
If rand()
is sub-par, then code should use other generators. Yet one can still use this approach to build up larger random numbers.
如果rand()低于标准,那么代码应该使用其他生成器。然而,人们仍然可以使用这种方法来建立更大的随机数。
#3
1
Iff you have a sufficiently good source of random bytes (like, say, /dev/random or /dev/urandom on a linux machine), you can simply consume 8 bytes from that source and concatenate them. If they are independent and have a linear distribution, you're set.
如果你有足够好的随机字节来源(例如,linux机器上的/ dev / random或/ dev / urandom),你可以简单地从该源消耗8个字节并连接它们。如果它们是独立的并且具有线性分布,那么你就可以了。
If you don't, you MAY get away by doing the same, but there is likely to be some artefacts in your pseudo-random generator that gives a toe-hold for all sorts of hi-jinx.
如果你不这样做,你也可以通过做同样的事情来逃避,但你的伪随机生成器中可能会有一些假象,它们可以为所有类型的hi-jinx提供保持。
Example code assuming we have an open binary FILE *source
:
假设我们有一个打开的二进制文件FILE *源的示例代码:
/* 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;
}
If you replace "read random bytes from a randomness device" with "get bytes from a function call", all you have to do is to adjust the shifts in method #2.
如果用“从函数调用中获取字节”替换“从随机设备中读取随机字节”,您所要做的就是调整方法#2中的移位。
You're vastly more likely to get a "number with many digits" than one with "small number of digits" (of all the numbers between 0 and 2 ** 64, roughly 95% have 19 or more decimal digits, so really that is what you will mostly get.
你很可能得到一个“有很多数字的数字”而不是“少数位”的数字(0到2之间的所有数字** 64,大约95%有十九位或更多十进制数字,所以真的那样是你最常得到的。
#4
0
I have tried this code here and it seems to work fine there.
我在这里试过这个代码,似乎在那里工作得很好。
#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;
}
I ran a few iterations and i get the following outputs :
我运行了几次迭代,得到以下输出:
value 1869044101095834648
value 2104046041914393000
值1869044101095834648值2104046041914393000
value 1587782446298476296
value 604955295827516250
value 41152208336759610
value 57792837533816000
值1587782446298476296值604955295827516250值41152208336759610价值57792837533816000
#5
0
If you don't mind a repetitive pseudo random sequence (hey, for 64 bits you aren't going to notice the repetition in your lifetime ;) and you can deal with one value less than your requested range (0 isn't going to happen), an LCG or MCG is an astoundingly simple solution. Wikipedia: Linear congruential generator Go to here to generate a couple prime numbers and use one for the modulus and the other for the multiplier below. (caveat: this sequence will be guessable and thus it is not secure)
如果你不介意重复的伪随机序列(嘿,64位你不会注意到你生命中的重复;)你可以处理一个小于你请求范围的值(0不会发生),LCG或MCG是一个非常简单的解决方案。*:线性同余生成器转到此处生成一对素数,并使用一个用于模数,另一个用于下面的乘数。 (告诫:这个序列是可猜测的,因此不安全)
#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
0
If you have 32 or 16-bit random value - generate 2 or 4 randoms and combine them to one 64-bit with <<
and |
.
如果你有32或16位随机值 - 生成2或4个randoms并将它们与< <和|组合成一个64位。< p>
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;
}
#7
-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;
}
#1
3
If you don't need cryptographically secure pseudo random numbers, I would suggest using MT19937-64. It is a 64 bit version of Mersenne Twister PRNG.
如果您不需要加密安全的伪随机数,我建议使用MT19937-64。它是Mersenne Twister PRNG的64位版本。
Please, do not combine rand()
outputs and do not build upon other tricks. Use existing implementation:
请不要组合rand()输出,也不要构建其他技巧。使用现有实施:
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
#2
3
Concerning "So results are always 18 digits or 20 digits."
关于“所以结果总是18位或20位”。
See @Thomas comment. If you generate random numbers long enough, code will create ones like 5, 11 and 33387. If code generates 1,000,000,000 numbers/second, it may take a year as very small numbers < 100,000 are so rare amongst all 64-bit numbers.
请参阅@Thomas评论。如果您生成足够长的随机数,代码将创建5,11和33387之类的代码。如果代码生成1,000,000,000个数字/秒,则可能需要一年,因为非常小的数字<100,000在所有64位数字中非常罕见。
rand()
simple returns random bits. A simplistic method pulls 1 bit at a time
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;
}
Assuming RAND_MAX
is some power of 2 - 1 as in OP's case 1073741823 == 0x3FFFFFFF
, take advantage that 30 bits are generated each time. The following code will call rand()
3 times - a tad wasteful. Instead bits shifted out could be saved for the next random number, but that brings in other issues. Leave that for another day.
假设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;
}
A portable loop count method avoids the 30
便携式循环计数方法避免了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;
}
The autocorrelation effects commented here are caused by a weak rand()
. C does not specify a particular method of random number generation. The above relies on rand()
- or whatever base random function employed - being good.
这里评论的自相关效应是由弱rand()引起的。 C没有指定随机数生成的特定方法。上面依赖于rand() - 或任何基本随机函数 - 是好的。
If rand()
is sub-par, then code should use other generators. Yet one can still use this approach to build up larger random numbers.
如果rand()低于标准,那么代码应该使用其他生成器。然而,人们仍然可以使用这种方法来建立更大的随机数。
#3
1
Iff you have a sufficiently good source of random bytes (like, say, /dev/random or /dev/urandom on a linux machine), you can simply consume 8 bytes from that source and concatenate them. If they are independent and have a linear distribution, you're set.
如果你有足够好的随机字节来源(例如,linux机器上的/ dev / random或/ dev / urandom),你可以简单地从该源消耗8个字节并连接它们。如果它们是独立的并且具有线性分布,那么你就可以了。
If you don't, you MAY get away by doing the same, but there is likely to be some artefacts in your pseudo-random generator that gives a toe-hold for all sorts of hi-jinx.
如果你不这样做,你也可以通过做同样的事情来逃避,但你的伪随机生成器中可能会有一些假象,它们可以为所有类型的hi-jinx提供保持。
Example code assuming we have an open binary FILE *source
:
假设我们有一个打开的二进制文件FILE *源的示例代码:
/* 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;
}
If you replace "read random bytes from a randomness device" with "get bytes from a function call", all you have to do is to adjust the shifts in method #2.
如果用“从函数调用中获取字节”替换“从随机设备中读取随机字节”,您所要做的就是调整方法#2中的移位。
You're vastly more likely to get a "number with many digits" than one with "small number of digits" (of all the numbers between 0 and 2 ** 64, roughly 95% have 19 or more decimal digits, so really that is what you will mostly get.
你很可能得到一个“有很多数字的数字”而不是“少数位”的数字(0到2之间的所有数字** 64,大约95%有十九位或更多十进制数字,所以真的那样是你最常得到的。
#4
0
I have tried this code here and it seems to work fine there.
我在这里试过这个代码,似乎在那里工作得很好。
#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;
}
I ran a few iterations and i get the following outputs :
我运行了几次迭代,得到以下输出:
value 1869044101095834648
value 2104046041914393000
值1869044101095834648值2104046041914393000
value 1587782446298476296
value 604955295827516250
value 41152208336759610
value 57792837533816000
值1587782446298476296值604955295827516250值41152208336759610价值57792837533816000
#5
0
If you don't mind a repetitive pseudo random sequence (hey, for 64 bits you aren't going to notice the repetition in your lifetime ;) and you can deal with one value less than your requested range (0 isn't going to happen), an LCG or MCG is an astoundingly simple solution. Wikipedia: Linear congruential generator Go to here to generate a couple prime numbers and use one for the modulus and the other for the multiplier below. (caveat: this sequence will be guessable and thus it is not secure)
如果你不介意重复的伪随机序列(嘿,64位你不会注意到你生命中的重复;)你可以处理一个小于你请求范围的值(0不会发生),LCG或MCG是一个非常简单的解决方案。*:线性同余生成器转到此处生成一对素数,并使用一个用于模数,另一个用于下面的乘数。 (告诫:这个序列是可猜测的,因此不安全)
#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
0
If you have 32 or 16-bit random value - generate 2 or 4 randoms and combine them to one 64-bit with <<
and |
.
如果你有32或16位随机值 - 生成2或4个randoms并将它们与< <和|组合成一个64位。< p>
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;
}
#7
-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;
}