我需要使用C生成64位无符号整数。即范围应为0
至18446744073709551615
。RAND_MAX
为1073741823
。
我在链接中找到一些解决方案,可能是重复的,但答案大多将一些rand()
结果连接在一起或进行一些递增算术运算。因此,结果始终为18位或20位数字。我也希望得到像5
、11
、33387
这样的结果,而不仅仅是3771778641802345472
。
顺便说一下,我真的没有太多关于C语言的经验,但任何方法、代码示例和想法都可能是有益的。
我需要使用C生成64位无符号整数。即范围应为0
至18446744073709551615
。RAND_MAX
为1073741823
。
我在链接中找到一些解决方案,可能是重复的,但答案大多将一些rand()
结果连接在一起或进行一些递增算术运算。因此,结果始终为18位或20位数字。我也希望得到像5
、11
、33387
这样的结果,而不仅仅是3771778641802345472
。
顺便说一下,我真的没有太多关于C语言的经验,但任何方法、代码示例和想法都可能是有益的。
关于“结果始终为18位或20位数字。”
请参见@Thomas的评论。如果您生成足够长时间的随机数,代码将创建像5、11和33387这样的数字。如果代码每秒生成1,000,000,000个数字,则可能需要一年的时间,因为在所有64位数字中,非常小的数字<100,000是非常罕见的。
rand()
简单返回随机位。一个简单的方法每次提取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
,每次会生成至少15位二进制数。以下代码将调用rand()
5次-有点浪费。相反,可以保存移位出来的位以供下一个随机数使用,但这会带来其他问题。请留待以后再处理。uint64_t rand_uint64(void) {
uint64_t r = 0;
for (int i=0; i<64; i += 15 /*30*/) {
r = r*((uint64_t)RAND_MAX + 1) + rand();
}
return r;
}
15 /*30*/
- 但请参见下面的2020编辑。#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;
}
自相关效应 在这里 所述是由于弱的 rand()
引起的。C语言没有指定特定的随机数生成方法。上述依赖于使用良好的 rand()
或其他基本随机函数。
如果 rand()
不够好,那么代码应该使用其他生成器。然而,仍然可以使用这种方法来构建更大的随机数。
[编辑于2020年]
Hallvard B. Furuseth 提供了一种很好的方法来确定当RAND_MAX
是Mersenne Number时,它包含的位数 - 即2的幂减1。
#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX)
_Static_assert((RAND_MAX & (RAND_MAX + 1u)) == 0, "RAND_MAX not a Mersenne number");
uint64_t rand64(void) {
uint64_t r = 0;
for (int i = 0; i < 64; i += RAND_MAX_WIDTH) {
r <<= RAND_MAX_WIDTH;
r ^= (unsigned) rand();
}
return r;
}
/* 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;
}
#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());
}
ll
。最好使用 "%016 PRIx64 \ n"
而不是 "%016 p \ n"
- 确保与 uint64_t
匹配的打印说明符。 (请参阅 <inttypes.h>
) - chux - Reinstate Monica我已经尝试了这段代码在这里,看起来它在那里运行得很好。
#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;
}
*
来构建值,如 a*b
,会破坏生成的值的分布。 (long)a*b
和 abs(e)
都可能导致有符号整数溢出 - 这是 未定义行为 (UB)。 abs()
返回一个 int
。当 int/long
范围不同时,使用 abs(some_long)
会产生额外的问题。 - chux - Reinstate Monica<<
和|
将它们合并为一个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;
}
RAND_MAX
的值,uint64_t r = rand(); r = r<<30 | rand(); r = r<<30 | rand();
是有意义的。但愿我能将其推到前几个答案。 - ESVRAND_MAX是2^30-1
,那么答案就是有意义的,正如OP所说的那样(i486的2的幂次方错误,差一)。如果使用r = r<<30 ^ rand();
(^
而不是|
),那么它甚至可以更好,因为这对于RAND_MAX是2^N-1,N>=30
,而不仅仅是N==30
是有意义的。 - chux - Reinstate Monica#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;
}
rand()
连接起来,否则会产生各种自相关效应,并且分布将不是均匀的。请参考:http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/c-lang.html - Bathsheba