[c] rand () + rand ()가 음수를 생성하는 이유는 무엇입니까?

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()));
}

누군가 두 번째 경우에 왜 음수가 표시되는지 설명 할 수 있습니까?

추신 : 루프 전에 시드를로 초기화합니다 srand(time(NULL)).



답변

rand()0와 사이의 정수를 반환하도록 정의되었습니다 RAND_MAX.

rand() + rand()

넘칠 수 있습니다. 관찰 한 것은 정수 오버플로로 인한 정의되지 않은 동작 의 결과 일 수 있습니다 .


답변

문제는 추가입니다. 값을 rand()반환합니다 . 따라서 두 개를 추가하면에 도달 할 수 있습니다. 이 초과 하면 추가 결과가 보유 할 수 있는 유효 범위를 초과합니다 . 부호있는 값의 오버플로는 정의되지 않은 동작이며 키보드가 외국 언어로 대화 할 수 있습니다.int0...RAND_MAXRAND_MAX * 2INT_MAXint

여기에 두 개의 임의 결과를 추가 할 때 얻는 이점이 없으므로 간단한 아이디어는 그렇게하지 않는 것입니다. 또는 unsigned int합계를 보유 할 수있는 경우 각 결과를 더하기 전에 캐스트 할 수 있습니다 . 또는 더 큰 유형을 사용하십시오. 참고 long보다 반드시 더 넓은 int동일한가 적용되는 long long경우에 int적어도 64 비트이다!

결론 : 추가를 피하십시오. 더 많은 “무작위”를 제공하지 않습니다. 더 많은 비트가 필요하면 값을 연결할 수도 sum = a + b * (RAND_MAX + 1)있지만보다 큰 데이터 유형이 필요할 수도 있습니다 int.

명시된 이유는 제로 결과를 피하는 것입니다. 두 rand()통화가 모두 0 일 수 있으므로 두 호출 의 결과를 추가하여 피할 수는 없습니다 . 대신 증분 할 수 있습니다. 경우 RAND_MAX == INT_MAX,이은으로 수행 할 수 없습니다 int. 그러나 (unsigned int)rand() + 1매우 가능성이 높습니다. UINT_MAX > INT_MAX필자가 알고있는 모든 구현에서 사실 이기 때문에 (최종적으로 아님) 가능성이 높습니다 ( 지난 30 년 동안 임베디드 아키텍처, DSP 및 모든 데스크탑, 모바일 및 서버 플랫폼을 포함합니다).

경고:

이미 여기 의견에 뿌려 있지만,이 개 임의의 값을 추가하면 않는하시기 바랍니다 참고 하지 얻을 : 균일 한 분포를 얻을 수 있지만, 두 개의 주사위를 압연 같은 삼각 분포는 12두 주사위 보여주고있다 (두 개의 주사위) 6. 를 위해 11: 거기에 이미 두 가지 변종이다 6 + 5또는 5 + 6등,

따라서이 측면에서도 추가가 나쁩니다.

또한 의사 난수 생성기에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);


답변

기본적으로 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 ()의 합으로 리턴 된 값이 RAND_MAX의 값을 초과하지 않도록하여 다소 까다로운 접근법을 시도 할 수 있습니다. 가능한 접근 방식은 sum = rand () / 2 + rand () / 2; 이렇게하면 두 rand가 모두 32767을 반환하더라도 RAND_MAX 값이 32767 인 16 비트 컴파일러의 경우에도 (32767/2 = 16383) 16383 + 16383 = 32766이므로 음의 합계가되지 않습니다.


답변

내가 추가 한 이유는 내 코드에서 임의의 숫자로 ‘0’을 피하는 것이 었습니다. rand () + rand ()는 내 마음에 들었던 빠른 더러운 솔루션이었습니다.

간단한 해결책 (좋아, “Hack”이라고 함)은 결코 제로 결과를 생성하지 않으며 오버플로하지 않습니다.

x=(rand()/2)+1    // using divide  -or-
x=(rand()>>1)+1   // using shift which may be faster
                  // compiler optimization may use shift in both cases

이렇게하면 최대 가치가 제한되지만 신경 쓰지 않으면 잘 작동합니다.


답변

0을 피하려면 다음을 시도하십시오.

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

포함해야합니다 limits.h.