我观察到rand()库函数在循环中只被调用一次时,它几乎总是产生正数。

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

但是当我添加两次rand()调用时,生成的数字现在有更多的负数。

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

有人能解释一下为什么我在第二种情况下看到负数吗?

PS:我在循环之前将种子初始化为srand(time(NULL))。


当前回答

要避免0,试试这个:

int rnumb = rand()%(INT_MAX-1)+1;

你需要包括限制。h。

其他回答

基本上rand()生成0和RAND_MAX之间的数字,在您的情况下生成2 RAND_MAX > INT_MAX。

可以对数据类型的最大值进行模数处理,以防止溢出。这当然会破坏随机数的分布,但rand只是一种快速获得随机数的方法。

#include <stdio.h>
#include <limits.h>

int main(void)
{
    int i=0;

    for (i=0; i<100; i++)
        printf(" %d : %d \n", rand(), ((rand() % (INT_MAX/2))+(rand() % (INT_MAX/2))));

    for (i=0; i<100; i++)
        printf(" %d : %ld \n", rand(), ((rand() % (LONG_MAX/2))+(rand() % (LONG_MAX/2))));

    return 0;
}

也许你可以尝试一种比较棘手的方法,确保2 rand()的sum返回的值永远不会超过RAND_MAX的值。一种可能的方法是sum = rand()/2 + rand()/2;这将确保对于RAND_MAX值为32767的16位编译器,即使两个rand都返回32767,即使(32767/2 = 16383)16383+16383 = 32766,也不会产生负和。

While what everyone else has said about the likely overflow could very well be the cause of the negative, even when you use unsigned integers. The real problem is actually using time/date functionality as the seed. If you have truly become familiar with this functionality you will know exactly why I say this. As what it really does is give a distance (elapsed time) since a given date/time. While the use of the date/time functionality as the seed to a rand(), is a very common practice, it really is not the best option. You should search better alternatives, as there are many theories on the topic and I could not possibly go into all of them. You add into this equation the possibility of overflow and this approach was doomed from the beginning.

那些发布rand()+1的人正在使用最常用的解决方案,以确保他们不会得到负数。但是,这种方法也不是最好的方法。

您能做的最好的事情是花费额外的时间来编写和使用适当的异常处理,如果和/或当您最终得到零结果时,只添加到rand()数字。正确处理负数。rand()功能并不完美,因此需要与异常处理一起使用,以确保最终得到所需的结果。

花费额外的时间和精力来调查、研究和正确地实现rand()功能是非常值得的。这只是我的个人意见。祝你好运……

这是对对这个回答的评论中提出的问题的澄清的回答,

我添加的原因是为了避免在我的代码中使用“0”作为随机数。Rand ()+ Rand()是我脑海中迅速出现的肮脏解决方案。

问题是避免0。提议的解决方案(至少)存在两个问题。一个是,正如其他答案所指出的,rand()+rand()可以调用未定义的行为。最好的建议是永远不要调用未定义的行为。另一个问题是,不能保证rand()不会连续两次产生0。

下面的语句拒绝0,避免未定义的行为,并且在绝大多数情况下将比两次调用rand()更快:

int rnum;
for (rnum = rand(); rnum == 0; rnum = rand()) {}
// or do rnum = rand(); while (rnum == 0);

谢谢。我添加的原因是为了避免在我的代码中使用“0”作为随机数。Rand ()+ Rand()是我脑海中迅速出现的肮脏解决方案

对我来说,这听起来像是一个XY问题,为了从rand()中不得到0,你调用rand()两次,使程序变慢,有一个新的挫折,得到0的可能性仍然存在。

另一个解决方案是使用uniform_int_distribution,它在定义的间隔内创建一个随机且均匀分布的数字:

https://wandbox.org/permlink/QKIHG4ghwJf1b7ZN

#include <random>
#include <array>
#include <iostream>
 
int main()
{
    const int MAX_VALUE=50;
    const int MIN_VALUE=1;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> distrib(MIN_VALUE, MAX_VALUE);
    std::array<int,MAX_VALUE-MIN_VALUE> weight={0};

    for(int i=0; i<50000; i++) {
        weight[distrib(gen)-MIN_VALUE]++;
    }
    
    for(int i=0;i<(int)weight.size();i++) {
        std::cout << "value: " << MIN_VALUE+i << " times: " << weight[i] << std::endl; 
    }
}