如何在C中生成随机整数?


Answers:


662

注意:请勿rand()用于安全性。如果您需要一个密码安全的号码,请参阅此答案

#include <time.h>
#include <stdlib.h>

srand(time(NULL));   // Initialization, should only be called once.
int r = rand();      // Returns a pseudo-random integer between 0 and RAND_MAX.

编辑:在Linux上,您可能更喜欢使用random和srandom


194
为简单起见+1,但强调srand()仅应调用一次可能是一个好主意。另外,在线程应用程序中,您可能要确保每个线程都存储生成器的状态,并为每个线程播种一次生成器。
RBerteig

41
@trusktr,它很复杂。原因是:time()每秒仅更改一次。如果您从播种time(),对于的每次调用rand(),那么您在一秒钟内的每次调用都会获得相同的值。但是更大的原因是,rand()对于这种用例来说,的属性和类似功能最适合用例,因为它们每次运行时仅被准确地植入一次,而不是在每个调用中都被植入。根据未经测试或未经验证的属性的“随机性”会导致麻烦。
RBerteig

9
一个简单的线性同余生成器(rand()通常是这种情况)的@trusktr rand()充其量根本没有作用,最坏的情况是会破坏该生成器的已知质量。这是一个很深的主题。首先阅读有关随机数的Knuth Vol 2第3章,作为对数学和陷阱的最佳介绍。
RBerteig

21
通过srand((unsigned int)time(NULL));
强制转换

9
请记住,这仍然是查看PRNG的较弱方法。就在去年,Linux上的一种加密锁型病毒随着时间的流逝而犯了一个错误,这大大减少了搜索空间。您所要做的就是获得感染发生时间的体面想法,然后从那时开始尝试播种。上次我听说,最好的随机性来源是/ dev / urandom,据推测,它是从诸如硬件温度之类的混乱来源混合而成的。但是,如果您真正想要的是程序在每次运行时都采取不同的行动,那么上述解决方案就可以了。
Jemenake'2

238

中的rand()函数<stdlib.h>返回介于0和之间的伪随机整数RAND_MAX。您可以srand(unsigned int seed)用来设置种子。

通常将%运算符与一起使用rand()以获取不同的范围(尽管请记住,这会在一定程度上降低一致性)。例如:

/* random int between 0 and 19 */
int r = rand() % 20;

如果您真正关心均匀性,则可以执行以下操作:

/* Returns an integer in the range [0, n).
 *
 * Uses rand(), and so is affected-by/affects the same seed.
 */
int randint(int n) {
  if ((n - 1) == RAND_MAX) {
    return rand();
  } else {
    // Supporting larger values for n would requires an even more
    // elaborate implementation that combines multiple calls to rand()
    assert (n <= RAND_MAX)

    // Chop off all of the values that would cause skew...
    int end = RAND_MAX / n; // truncate skew
    assert (end > 0);
    end *= n;

    // ... and ignore results from rand() that fall above that limit.
    // (Worst case the loop condition should succeed 50% of the time,
    // so we can expect to bail out of this loop pretty quickly.)
    int r;
    while ((r = rand()) >= end);

    return r % n;
  }
}

18
这是一种常见的做法,但不是正确的做法。看到这个这个
拉泽尔

35
@Lazer:这就是为什么我说“尽管请记住,这会在一定程度上降低一致性”。
劳伦斯·贡萨尔维斯

3
@AbhimanyuAryan这%是模运算符。它为您提供整数除法的余数,因此x % n将始终为您提供介于0和之间的数字n - 1(只要xn均为正数)。如果你仍然觉得迷惑,试着写一个程序,已经i数从0到100,并打印出i % n一些n你选择的小于100
劳伦斯·贡萨尔维斯

2
@necromancer我继续并添加了一个完全统一的解决方案。
劳伦斯·贡萨尔维斯

2
@Lazer您发布的第二个链接实际上仍然不够完美。强制转换为双向并没有帮助。您发布的第一个链接具有完美统一的解决方案,尽管对于较小的上限它会循环很多。我为这个答案添加了一个完全统一的解决方案,即使对于较小的上限也不应循环太多。
劳伦斯·贡萨尔维斯

53

如果您需要安全的随机字符或整数:

如何安全地以各种编程语言生成随机数所述,您需要执行以下操作之一:

例如:

#include "sodium.h"

int foo()
{
    char myString[32];
    uint32_t myInt;

    if (sodium_init() < 0) {
        /* panic! the library couldn't be initialized, it is not safe to use */
        return 1; 
    }


    /* myString will be an array of 32 random bytes, not null-terminated */        
    randombytes_buf(myString, 32);

    /* myInt will be a random number between 0 and 9 */
    myInt = randombytes_uniform(10);
}

randombytes_uniform() 是加密安全且无偏见的。


libsodium RNG应该在调用randombytes_buf之前播种吗?
user2199593

只是sodium_init()在某个时候打电话。不用担心RNG,它使用内核的。
Scott Arciszewski

注意:我批准了最近的编辑,sodium_init()尽管它不一定是我的示例的一部分,因为它是重要的细节。
Scott Arciszewski

29

让我们经历一下。首先,我们使用srand()函数为随机化器设定种子。基本上,计算机可以根据输入给srand()的数字生成随机数。如果给定相同的种子值,则每次都会生成相同的随机数。

因此,我们必须为随机化器播种一个始终在变化的值。我们通过使用time()函数向其提供当前时间的值来实现。

现在,当我们调用rand()时,每次都会产生一个新的随机数。

#include <stdio.h>

int random_number(int min_num, int max_num);

int main(void)
{
    printf("Min : 1 Max : 40 %d\n", random_number(1,40));
    printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));
    return 0;
}

int random_number(int min_num, int max_num)
{
    int result = 0, low_num = 0, hi_num = 0;

    if (min_num < max_num)
    {
        low_num = min_num;
        hi_num = max_num + 1; // include max_num in output
    } else {
        low_num = max_num + 1; // include max_num in output
        hi_num = min_num;
    }

    srand(time(NULL));
    result = (rand() % (hi_num - low_num)) + low_num;
    return result;
}

12
好的代码,但是调用'srand(time(NULL));'不是一个好主意。在for循环中调用时,此方法产生相同的数字。
RayOldProf

1
建议的涉及代码的编辑通常会被拒绝。有人在这里发表评论“算法错误。可能会产生比最大值更大的数字”。自己还没有评估过此要求。
马丁·史密斯

1
@Martin Smith问题:1)应该是else{ low_num=max_num; hi_num=min_num+1;2)失败时hi_num - low_num > INT_MAX。3)在极少数情况下忽略值INT_MAX > hi_num - low_num > RAND_MAX
chux-恢复莫妮卡

1
如果在同一秒内多次调用此函数,则将其重新生成将导致此函数产生相同的数字。如果您真的想播种,那么每秒只能播种一次。
艾丽卡

1
轻微:hi_num = max_num + 1;缺乏防溢出保护。
chux-恢复莫妮卡

25

如果您需要比stdlib提供的质量更好的伪随机数,请查看Mersenne Twister。它也更快。示例实现很多,例如在这里


2
+1:看起来很酷,但我只是在做一个猜谜游戏。如果要在业务应用程序中使用随机数生成器,那么我肯定会使用它。
Kredns

4
不要使用Mersenne Twister,而要使用诸如xoroshiro128 +或PCG之类的好东西。(相关链接。)
Veedrac '16

17

标准C函数是rand()。足够为单人纸牌发卡,但是这很糟糕。rand()循环执行很短的数字列表的许多实现方式,低位具有较短的循环。一些程序调用的rand()方式很糟糕,并且srand()很难计算出要传递的良好种子。

在C中生成随机数的最好方法是使用第三方库,例如OpenSSL。例如,

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>

/* Random integer in [0, limit) */
unsigned int random_uint(unsigned int limit) {
    union {
        unsigned int i;
        unsigned char c[sizeof(unsigned int)];
    } u;

    do {
        if (!RAND_bytes(u.c, sizeof(u.c))) {
            fprintf(stderr, "Can't get random bytes!\n");
            exit(1);
        }
    } while (u.i < (-limit % limit)); /* u.i < (2**size % limit) */
    return u.i % limit;
}

/* Random double in [0.0, 1.0) */
double random_double() {
    union {
        uint64_t i;
        unsigned char c[sizeof(uint64_t)];
    } u;

    if (!RAND_bytes(u.c, sizeof(u.c))) {
        fprintf(stderr, "Can't get random bytes!\n");
        exit(1);
    }
    /* 53 bits / 2**53 */
    return (u.i >> 11) * (1.0/9007199254740992.0);
}

int main() {
    printf("Dice: %d\n", (int)(random_uint(6) + 1));
    printf("Double: %f\n", random_double());
    return 0;
}

为什么需要那么多代码?其他语言(例如Java和Ruby)具有用于随机整数或浮点数的函数。OpenSSL仅提供随机字节,因此我尝试模仿Java或Ruby如何将其转换为整数或浮点数。

对于整数,我们要避免模偏差。假设我们从中获得了一些随机的4位整数rand() % 10000,但是rand()只能返回0到32767(就像在Microsoft Windows中一样)。从0到2767的每个数字比在从2768到9999的每个数字出现的频率更高。要消除偏差,我们可以rand()在值小于2768时重试,因为从2768到32767的30000值均匀映射到从0到2767 的10000个值。 9999。

对于浮点数,我们需要53个随机位,因为a double拥有53位的精度(假设它是IEEE的两倍)。如果我们使用超过53位,则会得到舍入偏差。一些程序员编写类似的代码rand() / (double)RAND_MAX,但rand()可能只返回31位,或者在Windows中仅返回15位。

OpenSSL的RAND_bytes()种子本身,也许是/dev/urandom在Linux中阅读的。如果我们需要许多随机数,那么从中读取所有随机数将太慢/dev/urandom,因为必须从内核复制它们。允许OpenSSL从种子生成更多随机数的速度更快。

有关随机数的更多信息:


感谢您的扩展回答。请注意,在该问题的24个当前答案中,您是唯一一个具有额外解释来处理float/的答案double,因此我已澄清了该问题,请坚持使用int数字,以免使其过于宽泛。有与专门处理其他C问题float/ double随机值,所以你可能需要将你的答案下半年转贴到这样的问题stackoverflow.com/questions/13408990/...
心教堂

11

如果您的系统支持该arc4random功能家族,我建议您使用这些rand功能代替标准功能。

arc4random系列产品包括:

uint32_t arc4random(void)
void arc4random_buf(void *buf, size_t bytes)
uint32_t arc4random_uniform(uint32_t limit)
void arc4random_stir(void)
void arc4random_addrandom(unsigned char *dat, int datlen)

arc4random 返回一个随机的32位无符号整数。

arc4random_buf在参数中放入随机内容buf : void *。内容量由bytes : size_t参数确定。

arc4random_uniform返回遵循规则:的随机32位无符号整数0 <= arc4random_uniform(limit) < limit,其中limit也是无符号32位整数。

arc4random_stir从中读取数据/dev/urandom并将数据传递给该数据,arc4random_addrandom以另外对其内部随机数池进行随机化。

arc4random_addrandom用于arc4random_stir根据传递给它的数据填充其内部随机数池。

如果您没有这些功能,但是在Unix上,则可以使用以下代码:

/* This is C, not C++ */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h> /* exit */
#include <stdio.h> /* printf */

int urandom_fd = -2;

void urandom_init() {
  urandom_fd = open("/dev/urandom", O_RDONLY);

  if (urandom_fd == -1) {
    int errsv = urandom_fd;
    printf("Error opening [/dev/urandom]: %i\n", errsv);
    exit(1);
  }
}

unsigned long urandom() {
  unsigned long buf_impl;
  unsigned long *buf = &buf_impl;

  if (urandom_fd == -2) {
    urandom_init();
  }

  /* Read 4 bytes, or 32 bits into *buf, which points to buf_impl */
  read(urandom_fd, buf, sizeof(long));
  return buf_impl;
}

urandom_init函数打开/dev/urandom设备,并把该文件描述符urandom_fd

urandom函数与调用基本上相同rand,但更加安全,并且返回long(易于更改)。

但是,/dev/urandom速度可能会有些慢,因此建议您将其用作其他随机数生成器的种子。

如果您的系统没有/dev/urandom,但确实有一个/dev/random或类似的文件,那么你可以简单地改变传递到路径openurandom_init。(我认为)POSIX中使用的urandom_initurandom它们的调用和API 符合POSIX,因此,即使不是所有POSIX兼容系统,它们也应该可以在大多数系统上工作。

注意:/dev/urandom如果没有足够的熵,则不会阻止读操作,因此在这种情况下生成的值可能在密码上不安全。如果您对此感到担心,请使用/dev/random,如果熵不足,它将始终阻止。

如果您在另一个系统(即Windows)上,请使用rand或某些内部Windows特定于平台的非便携式API。

包装功能urandomrandarc4random来电:

#define RAND_IMPL /* urandom(see large code block) | rand | arc4random */

int myRandom(int bottom, int top){
    return (RAND_IMPL() % (top - bottom)) + bottom;
}

8

C不存在STL。您必须致电rand,或者更好random。这些在标准库头中声明stdlib.hrand是POSIX,random是BSD规范功能。

rand和之间的区别在于,randomrandom返回更多可用的32位随机数,并且rand通常返回16位数字。BSD手册页显示的低位rand是循环且可预测的,因此rand对于较小的数字可能没有用。


3
@Neil-既然到目前为止所有答案都提到了STL,所以我怀疑问题已被快速编辑以删除不必要的参考。
迈克尔·伯尔

rand()对于小数不是没有用的-如果您确实需要,可以将它们移出位并仅使用更多随机的高位。
克里斯·卢茨

@Chris,如果知道随机数的大小,则可以,但是如果运行时所需的随机数大小发生变化(例如,对动态数组进行混洗等),将很难解决这种警告。
dreamlax

在这里找不到任何随机函数:-(
kasia.b 2014年

@ kasia.b在该链接中有extern int rand(void);extern void srand(unsigned int);
拉斯塔吉迪

7

看一下ISAAC(间接,移位,累加,添加和计数)。它的分布均匀,平均周期为2 ^ 8295。


2
ISAAC是一种有趣的RNG,因为它的速度很快,但尚未受到严重的密码学关注。
user2398029 2014年

4

这是在选择的两个数字之间获取随机数的好方法。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

    #define randnum(min, max) \
        ((rand() % (int)(((max) + 1) - (min))) + (min))

int main()
{
    srand(time(NULL));

    printf("%d\n", randnum(1, 70));
}

第一次输出:39

第二次输出:61

第三次输出:65

您可以将其后的值更改为randnum您选择的任何数字,这将为您在这两个数字之间生成一个随机数。


4

您要使用rand()。注意(非常重要):确保为rand函数设置种子。如果不这样做,那么您的随机数并不是真正的随机数。这非常非常重要。幸运的是,您通常可以结合使用系统滴答计时器和日期来获得良好的种子。


6
有两点:a)无论您如何生成发生器,您的随机数都不是“真正的”随机数。b)在许多情况下(例如,进行测试)使伪随机序列始终相同非常方便。

16
如果非常重要的是您的数字是真正随机的,则不应使用rand()函数。
tylerl

1
无论是否设置种子,rand的值都不是“真正”随机的。给定已知种子,该序列是可预测的。“真正”随机数的生成是困难的。兰特不涉及熵。
dreamlax

2
当然会的-生成器由库为您播种(可能为零,但这是有效的种子)。

4
嗯,但是已知的算法/已知种子对于调试任何使用随机数的程序都是必不可少的。记录使用的种子和模拟运行并不罕见,以便可以重新创建它以进行更详细的分析。完全不调用srand()等效于调用srand(1)。
RBerteig

4

FWIW,答案是肯定的,有一个stdlib.h叫做的函数rand。此功能主要针对速度和分布进行了调整,而不是出于不可预测性。默认情况下,几乎所有用于各种语言和框架的内置随机函数都使用此函数。还有一些“密码学”的随机数生成器,它们的可预测性要低得多,但运行速度要慢得多。这些应在任何与安全性相关的应用程序中使用。


4

希望这比使用更加随机srand(time(NULL))

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    srand((unsigned int)**main + (unsigned int)&argc + (unsigned int)time(NULL));
    srand(rand());

    for (int i = 0; i < 10; i++)
        printf("%d\n", rand());
}

1
如果在1秒内多次执行此程序,则添加srand(rand())不会增加序列的随机性。time(NULL)仍将为它们每个返回相同的值,第一个rand()将返回相同的long,第二个对srand()的调用将具有相同的值,从而仍然具有相同的随机序列。仅在保证每次执行程序时此地址都不同时,使用argc的地址才有帮助,但这并不总是正确的。
theferrit32 '18

3

好吧,STL是C ++,而不是C,所以我不知道您想要什么。但是,如果需要C,则提供rand()srand()功能:

int rand(void);

void srand(unsigned seed);

这些都是ANSI C的一部分。还有以下random()功能:

long random(void);

但据我所知,random()这不是标准的ANSIC。第三方库可能不是一个坏主意,但这取决于您真正需要生成的数字的随机性。


3

C程序生成9到50之间的随机数

#include <time.h>
#include <stdlib.h>

int main()
{
    srand(time(NULL));
    int lowerLimit = 10, upperLimit = 50;
    int r =  lowerLimit + rand() % (upperLimit - lowerLimit);
    printf("%d", r);
}

通常,我们可以在lowerLimit和upperLimit-1之间生成一个随机数

即lowerLimit是包含性的,或者说r∈[lowerLimit,upperLimit)


@Pang这就是我清楚地提到9至50没有从9和50
Shivam K. THAKKAR

2
您的取模操作引入了偏差。
jww

2

rand() 是生成随机数最方便的方法。

您也可以从任何在线服务(例如random.org)中获取随机数。


1
您也可以从像random.org任何在线服务,赶上随机数赏金如果包括便携,高效的方式下做到这一点
MD XF

2
#include <stdio.h>
#include <stdlib.h>

void main() 
{
    int visited[100];
    int randValue, a, b, vindex = 0;

    randValue = (rand() % 100) + 1;

    while (vindex < 100) {
        for (b = 0; b < vindex; b++) {
            if (visited[b] == randValue) {
                randValue = (rand() % 100) + 1;
                b = 0;
            }
        }

        visited[vindex++] = randValue;
    }

    for (a = 0; a < 100; a++)
        printf("%d ", visited[a]);
}

然后在顶部使用变量@ b4hand定义
Muhammad Sadiq

在我发表评论时,我没有通用的编辑权限,通常更改实际答案的代码更改将被拒绝。如果您不希望解决问题,我可以。
b4hand

如果您打算产生唯一值的随机排列,则此代码仍然存在错误。它两次产生值84,而不产生值48。此外,它不为随机数生成器提供种子,因此每次执行时的顺序都相同。
b4hand

1
变量a和b是在此代码中定义的。它是无错误的。也没有语法和逻辑错误。
穆罕默德·萨迪克

不正确 正如我提到的,我已经手工确认了输出。
b4hand

1
#include <stdio.h>
#include <dos.h>

int random(int range);

int main(void)
{
    printf("%d", random(10));
    return 0;
}

int random(int range)
{
    struct time t;
    int r;

    gettime(&t);
    r = t.ti_sec % range;
    return r;
}

1

在现代的x86_64 CPU上,您可以通过以下方式使用硬件随机数生成器: _rdrand64_step()

示例代码:

#include <immintrin.h>

uint64_t randVal;
if(!_rdrand64_step(&randVal)) {
  // Report an error here: random number generation has failed!
}
// If no error occured, randVal contains a random 64-bit number

1
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

//generate number in range [min,max)
int random(int min, int max){
    int number = min + rand() % (max - min);
    return number; 
}

//Driver code
int main(){
    srand(time(NULL));
    for(int i = 1; i <= 10; i++){
        printf("%d\t", random(10, 100));
    }
    return 0;
}

0

听到一个很好的解释,为什么用rand()一个给定范围内的均匀分布的随机数产生一个不好的主意,我决定看一下输出的实际偏差。我的测试用例是掷骰子。这是C代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[])
{
    int i;
    int dice[6];

    for (i = 0; i < 6; i++) 
      dice[i] = 0;
    srand(time(NULL));

    const int TOTAL = 10000000;
    for (i = 0; i < TOTAL; i++)
      dice[(rand() % 6)] += 1;

    double pers = 0.0, tpers = 0.0;
    for (i = 0; i < 6; i++) {
      pers = (dice[i] * 100.0) / TOTAL;
      printf("\t%1d  %5.2f%%\n", dice[i], pers);
      tpers += pers;
    }
    printf("\ttotal:  %6.2f%%\n", tpers);
}

这是它的输出:

 $ gcc -o t3 t3.c
 $ ./t3 
        1666598  16.67%     
        1668630  16.69%
        1667682  16.68%
        1666049  16.66%
        1665948  16.66%
        1665093  16.65%
        total:  100.00%
 $ ./t3     
        1667634  16.68%
        1665914  16.66%
        1665542  16.66%
        1667828  16.68%
        1663649  16.64%
        1669433  16.69%
        total:  100.00%

我不知道您需要多少随机数,但是上面的代码足以满足大多数需求。

编辑:用比更好的方法初始化PRNG是个好主意time(NULL)


rand()可能无法通过其他随机性测试,例如diehard测试。rand()因平台而异;来自GNU / Linux的rand()值可能比来自BSD或Windows的值好。
George Koehler

这不是测试随机性的有效方法。
Veedrac'8

取决于目的和威胁/风险模型。对于加密强度较高的RNG-当然,请使用RDRAND(或RDSEED)。对于简单的掷骰子(不是赌场级别的恕我直言),上述内容就足够了。关键字是“ 足够好”。
鼠标

0

我在最近的应用程序中遇到了一个伪随机数生成器的严重问题:我通过pyhton脚本反复调用了我的C程序,并且使用以下代码作为种子:

srand(time(NULL))

但是,由于:

  • rand将生成相同的伪随机序列,并赋予rand中相同的种子(请参见 man srand);
  • 如前所述,时间函数仅从秒变化到秒:如果您的应用程序在同一秒内运行了多次,time则每次将返回相同的值。

我的程序生成相同的数字序列。您可以做三件事来解决这个问题:

  1. 将时间输出与运行中其他一些信息更改(在我的应用程序中,输出名称):

    srand(time(NULL) | getHashOfString(outputName))

    我使用djb2作为我的哈希函数。

  2. 增加时间分辨率。在我的平台clock_gettime上可用,因此我使用它:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec);
  3. 一起使用两种方法:

    #include<time.h>
    struct timespec nanos;
    clock_gettime(CLOCK_MONOTONIC, &nanos)
    srand(nanos.tv_nsec | getHashOfString(outputName));

选项3(据我所知)可确保您获得最佳的种子随机性,但它可能仅在非常快速的应用程序上会产生差异。我认为选项2是一个不错的选择。


即使有了这些试探法,也不要依赖rand()获得加密数据。
domenukk '19

rand()我同意,不应将其用于加密数据。至少对我来说,我的应用程序不涉及加密数据,因此对我来说,使用给定的方法是可以的。
科达尔

0

尽管rand()这里有很多人的建议,但rand()除非有必要,否则您还是不想使用!rand()产生的随机数通常非常糟糕。引用Linux手册页:

的版本 rand()srand()Linux的C库中使用相同的随机数发生器random(3)srandom(3),所以低位应是随机的高阶位。但是,在较早的rand()实现和当前在不同系统上的实现中,低阶位的随机性要比高阶位的随机性小得多。当需要良好的随机性时,请勿在打算用于便携式应用程序中使用此功能。(改为使用random(3)

关于可移植性,random()POSIX标准也定义了相当长的时间。rand()较旧,它已经出现在第一个POSIX.1规范(IEEE Std 1003.1-1988)中,而random()第一次出现在POSIX.1-2001(IEEE Std 1003.1-2001)中,但是当前的POSIX标准已经是POSIX.1-2008 (IEEE Std 1003.1-2008),仅在一年前收到更新(IEEE Std 1003.1-2008,2016版)。所以我认为random()它非常便携。

POSIX.1-2001还介绍了lrand48()mrand48()功能,请参见此处

该函数系列应使用线性同余算法和48位整数算术生成伪随机数。

相当不错的伪随机源是 arc4random()许多系统上可用功能。它不是任何正式标准的一部分,它于1997年左右出现在BSD中,但是您可以在Linux和macOS / iOS等系统上找到它。


random()在Windows上不存在。
比约恩·林奎斯特

@BjörnLindqvistWindows也不是POSIX系统;它几乎是市场上唯一不至少支持基本POSIX API的系统(甚至锁定了iOS等系统也支持)。Windows仅受支持,rand()因为C标准也需要它。像往常一样,对于其他任何事情,您仅需要Windows的特殊解决方案即可。#ifdef _WIN32在跨平台代码中,该短语是您最常支持Windows的短语,通常,有一种解决方案适用于所有系统,而只有Windows才需要。
梅基

0

对于Linux C应用程序:

这是我根据上面的C语言实践得到的答案中经过重做的代码,并返回了任意大小的随机缓冲区(带有正确的返回码等)。确保urandom_open()在程序开始时调用一次。

int gUrandomFd = -1;

int urandom_open(void)
{
    if (gUrandomFd == -1) {
        gUrandomFd = open("/dev/urandom", O_RDONLY);
    }

    if (gUrandomFd == -1) {
        fprintf(stderr, "Error opening /dev/urandom: errno [%d], strerrer [%s]\n",
                  errno, strerror(errno));
        return -1;
    } else {
        return 0;
    }
}


void urandom_close(void)
{
    close(gUrandomFd);
    gUrandomFd = -1;
}


//
// This link essentially validates the merits of /dev/urandom:
// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
//
int getRandomBuffer(uint8_t *buf, int size)
{
    int ret = 0; // Return value

    if (gUrandomFd == -1) {
        fprintf(stderr, "Urandom (/dev/urandom) file not open\n");
        return -1;
    }

    ret = read(gUrandomFd, buf, size);

    if (ret != size) {
        fprintf(stderr, "Only read [%d] bytes, expected [%d]\n",
                 ret, size);
        return -1;
    } else {
        return 0;
    }
}

-2

我的简约解决方案应该适用于范围内的随机数[min, max)srand(time(NULL))在调用功能之前使用。

int range_rand(int min_num, int max_num) {
    if (min_num >= max_num) {
        fprintf(stderr, "min_num is greater or equal than max_num!\n"); 
    }
    return min_num + (rand() % (max_num - min_num));
} 

-3

尝试一下,我将其与上面已经提到的一些概念放在一起:

/*    
Uses the srand() function to seed the random number generator based on time value,
then returns an integer in the range 1 to max. Call this with random(n) where n is an integer, and you get an integer as a return value.
 */

int random(int max) {
    srand((unsigned) time(NULL));
    return (rand() % max) + 1;
}

16
这段代码不好。调用srand()要调用每次rand()是一个可怕的想法。由于time()通常以为单位返回一个值,因此快速调用此函数将返回相同的“随机”值。
高炉

3
该函数将与Unix random()函数混淆。
George Koehler
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.