有没有一个函数生成一个随机int数在C?或者我必须使用第三方库?


当前回答

<stdlib.h>中的rand()函数返回一个介于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;
  }
}

其他回答

我们来看看这个。首先,我们使用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;
    }

下面是我的方法(围绕rand()的包装器):

我还扩展到允许min为INT_MIN而max为INT_MAX的情况,这通常不可能单独使用rand(),因为它返回从0到RAND_MAX的值,包括(1/2范围)。

像这样使用它:

const int MIN = 1;
const int MAX = 1024;
// Get a pseudo-random number between MIN and MAX, **inclusive**.
// Seeding of the pseudo-random number generator automatically occurs
// the very first time you call it.
int random_num = utils_rand(MIN, MAX);

定义和氧描述:

#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>

/// \brief      Use linear interpolation to rescale, or "map" value `val` from range
///             `in_min` to `in_max`, inclusive, to range `out_min` to `out_max`, inclusive.
/// \details    Similar to Arduino's ingenious `map()` function:
///             https://www.arduino.cc/reference/en/language/functions/math/map/
///
/// TODO(gabriel): turn this into a gcc statement expression instead to prevent the potential for
/// the "double evaluation" bug. See `MIN()` and `MAX()` above.
#define UTILS_MAP(val, in_min, in_max, out_min, out_max) \
    (((val) - (in_min)) * ((out_max) - (out_min)) / ((in_max) - (in_min)) + (out_min))

/// \brief      Obtain a pseudo-random integer value between `min` and `max`, **inclusive**.
/// \details    1. If `(max - min + 1) > RAND_MAX`, then the range of values returned will be
///             **scaled** to the range `max - min + 1`, and centered over the center of the
///             range at `(min + max)/2`. Scaling the numbers means that in the case of scaling,
///             not all numbers can even be reached. However, you will still be assured to have
///             a random distribution of numbers across the full range.
///             2. Also, the first time per program run that you call this function, it will
///             automatically seed the pseudo-random number generator with your system's
///             current time in seconds.
/// \param[in]  min         The minimum pseudo-random number you'd like, inclusive. Can be positive
///                         OR negative.
/// \param[in]  max         The maximum pseudo-random number you'd like, inclusive. Can be positive
///                         OR negative.
/// \return     A pseudo-random integer value between `min` and `max`, **inclusive**.
int utils_rand(int min, int max)
{
    static bool first_run = true;
    if (first_run)
    {
        // seed the pseudo-random number generator with the seconds time the very first run
        time_t time_now_sec = time(NULL);
        srand(time_now_sec);
        first_run = false;
    }

    int range = max - min + 1;
    int random_num = rand();  // random num from 0 to RAND_MAX, inclusive

    if (range > RAND_MAX)
    {
        static_assert(
            sizeof(long int) > sizeof(int),
            "This must be true or else the below mapping/scaling may have undefined overflow "
            "and not work properly. In such a case, try casting to `long long int` instead of "
            "just `long int`, and update this static_assert accordingly.");

        random_num = UTILS_MAP((long int)random_num, (long int)0, (long int)RAND_MAX, (long int)min,
                               (long int)max);
        return random_num;
    }

    // This is presumably a faster approach than the map/scaling function above, so do this faster
    // approach below whenever you don't **have** to do the more-complicated approach above.
    random_num %= range;
    random_num += min;

    return random_num;
}

参见:

[我在写下上面的答案后发现了这个问答,但它显然非常相关,他们对非缩放范围的情况做了同样的事情]我如何从rand()中获得特定的数字范围? [我需要进一步研究和阅读这个答案-似乎有一些好的观点,保持良好的随机性不使用模量]我如何从rand()得到一个特定的数字范围? http://c-faq.com/lib/randrange.html

有人很好地解释了为什么使用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%

我不知道你需要你的随机数有多统一,但上面的看起来足够统一,满足大多数需求。

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

看看ISAAC(间接,移动,积累,添加和计数)。它是均匀分布的,平均循环长度为2^8295。

<stdlib.h>中的rand()函数返回一个介于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;
  }
}