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()
반환합니다 . 따라서 두 개를 추가하면에 도달 할 수 있습니다. 이 초과 하면 추가 결과가 보유 할 수 있는 유효 범위를 초과합니다 . 부호있는 값의 오버플로는 정의되지 않은 동작이며 키보드가 외국 언어로 대화 할 수 있습니다.int
0...RAND_MAX
RAND_MAX * 2
INT_MAX
int
여기에 두 개의 임의 결과를 추가 할 때 얻는 이점이 없으므로 간단한 아이디어는 그렇게하지 않는 것입니다. 또는 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
.