如何在C中生成随机64位无符号整数

时间:2015-10-08 08:03:50

标签: c random unsigned-integer

我需要使用C生成随机64位无符号整数。我的意思是,范围应该是018446744073709551615RAND_MAX1073741823

我在链接中找到了一些可能重复的解决方案,但答案主要是连接一些rand()结果或进行一些增量算术运算。所以结果总是18位或20位。我还想要51133387等结果,而不只是3771778641802345472

顺便说一句,我对C的确没有太多经验,但任何方法,代码示例和想法都可能是有益的。

7 个答案:

答案 0 :(得分:4)

如果您不需要加密安全的伪随机数,我建议您使用MT19937-64。它是Mersenne Twister PRNG的64位版本。

请不要将rand()输出结合起来,也不要建立其他技巧。使用现有的实施:

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html

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