C에서 임의의 int를 생성하는 방법은 무엇입니까?


답변:


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));
GiovaMaster

9
이 방법은 여전히 ​​PRNG를 보는 데 약한 방법입니다. 작년에 Linux의 cryptolocker 유형 바이러스는 시간이 지남에 따라 시드 오류를 일으켜 검색 공간을 크게 줄였습니다. 감염이 언제 발생했는지에 대한 적절한 아이디어를 얻은 다음 그 시점부터 씨앗을 시험해보기 만하면됩니다. 마지막으로, 랜덤의 가장 좋은 소스는 / dev / urandom인데, 아마도 하드웨어의 온도와 같은 혼란스러운 소스의 매시업에서 나온 것입니다. 그러나 실제로 원하는 것이 프로그램이 각 실행에서 다르게 작동하는 것이라면 위의 솔루션이 좋습니다.
Jemenake

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
그것은 일반적인 관행 이지만, 올바른 것은 아닙니다. 참조 .
Lazer

35
@Lazer : 이것이 "이것이 균일 성을 다소 떨어 뜨린다는 점을 명심해야한다"고 말한 이유입니다.
Laurence Gonsalves

3
@AbhimanyuAryan %모듈러스 연산자입니다. 너무, 당신에게 정수 나눗셈의 나머지를 제공 x % n항상 사이 당신에게 수를 줄 것이다 0n - 1(긴만큼 x하고 n모두 긍정적). 당신은 여전히 혼란을 찾을 경우, 한 프로그램을 작성하려고 i0에서 100까지 셀을, 밖으로 인쇄 i % n일부에 대한 n당신의 선택의보다 작은 100
로렌스 Gonsalves

2
@necromancer 나는 계속해서 완벽하게 균일 한 솔루션을 추가했습니다.
Laurence Gonsalves

2
@Lazer 게시 한 두 번째 링크는 실제로 여전히 완벽하지 않습니다. 더블과 백으로 캐스팅해도 도움이되지 않습니다. 게시 한 첫 번째 링크는 완벽하게 균일 한 솔루션을 제공하지만 작은 상한 에는 많은 루프가 발생 합니다. 이 답변에 완벽하게 균일 한 솔루션을 추가하여 작은 상한에도 루프가 발생하지 않아야합니다.
Laurence Gonsalves

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() 암호화 적으로 안전하고 편견이 없습니다.


randombytes_buf를 호출하기 전에 libsodium RNG를 시드해야합니까?
user2199593

sodium_init()어느 시점에서 전화하십시오 . RNG에 대해 걱정하지 마십시오. 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
코드와 관련하여 제안 된 수정 사항은 종종 거부됩니다. 누군가가 여기에 하나를 만든 주석과 "알고리즘 잘못이었다. 최대 값보다 더 큰 숫자를 생산할 수 있습니다." 주장을 직접 평가하지 않았습니다.
Martin Smith

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-Reinstate Monica

1
이렇게 다시 시드하면이 함수가 같은 초에 여러 번 호출되는 경우 같은 숫자를 생성합니다. 정말로 다시 시드하려면 초당 1 회만 시드하십시오.
Élektra

1
경미 : hi_num = max_num + 1;오버 플로우에 대한 보호가 부족합니다.
chux-복원 모니카

25

stdlib제공하는 것보다 더 나은 품질의 의사 난수가 필요한 경우 Mersenne Twister를 확인하십시오 . 더 빠릅니다. 예를 들어 샘플 구현이 풍부합니다. 여기 합니다 .


2
+1 : 근사해 보이지만 추측 게임을하고있었습니다. 비즈니스 응용 프로그램에서 난수 생성기를 사용하려는 경우 분명히 이것을 사용합니다.
Kredns

4
Mersenne Twister를 사용하지 말고 xoroshiro128 + 또는 PCG와 같은 좋은 것을 사용하십시오. (관련 링크)
Veedrac

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()Microsoft Windows에서와 같이 0에서 32767까지만 반환 할 수 있다고 가정합니다 . 0에서 2767 사이의 각 숫자는 2768에서 9999 사이의 각 숫자보다 자주 나타납니다. 바이어스를 제거하기 위해 다시 시도 할 수 있습니다.rand() 값이 2768 미만인 동안 2768에서 32767의 30000 값은 0에서 10000 값까지 균일하게 맵핑되기 때문입니다. 9999.

float의 경우 double53 비트의 정밀도를 유지 하기 때문에 53 개의 임의 비트가 필요 합니다 (IEEE 이중이라고 가정). 53 비트 이상을 사용하면 반올림 바이어스가 발생합니다. 일부 프로그래머는와 같은 코드를 작성 rand() / (double)RAND_MAX하지만 rand()Windows에서는 31 비트 또는 15 비트 만 반환 할 수 있습니다.

RAND_bytes()아마도 /dev/urandom리눅스에서 읽음으로써 OpenSSL의 시드 자체 . 임의의 숫자가 많이 필요한 경우 /dev/urandom커널에서 복사해야하므로 모두에서 읽기가 너무 느립니다 . OpenSSL이 시드에서 더 많은 난수를 생성하는 것이 더 빠릅니다.

난수에 대한 추가 정보 :

  • Perl의 Perl_seed () 는 C에서 시드를 계산하는 방법의 예입니다 srand(). 읽을 수없는 경우 현재 시간의 비트, 프로세스 ID 및 일부 포인터를 혼합 /dev/urandom합니다.
  • OpenBSD의 arc4random_uniform ()은 모듈로 바이어스를 설명합니다.
  • java.util.Random 용 Java API 는 임의의 정수에서 바이어스를 제거하고 53 비트를 임의의 부동 소수점으로 패킹하는 알고리즘을 설명합니다.

이 확장 된 답변에 감사드립니다. 이 질문에 대한 24 개의 현재 답변 중 귀하는 float/ 을 처리 할 수있는 추가 해석을 할 수있는 유일한 사람 double이므로 int너무 광범위하게 만들지 않기 위해 숫자를 고수하는 질문을 분명히 했습니다. 특별히 float/ double임의의 값을 다루는 다른 C 질문이 있으므로 stackoverflow.com/questions/13408990/…
Cœur

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_addrandomarc4random_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또는 유사한 파일을, 당신은 단순히 전달 경로를 변경할 수 open있는을 urandom_init. POSIX와 호환 urandom_init되고 사용되는 호출 및 API urandom는 POSIX 호환 시스템이 아니라면 대부분 작동합니다.

참고 : /dev/urandom사용 가능한 엔트로피가 충분하지 않은 경우 읽은 내용은 차단되지 않으므로 이러한 상황에서 생성 된 값은 암호화 적으로 안전하지 않을 수 있습니다. 걱정 /dev/random이되는 경우 엔트로피가 충분하지 않으면 항상 차단하는를 사용하십시오.

다른 시스템 (예 : Windows)을 사용하는 경우 rand또는 일부 내부 Windows 특정 플랫폼 종속 비 휴대용 API를 사용하십시오.

함수에 대한 래퍼 urandom, rand또는 arc4random전화 :

#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.h있습니다. randPOSIX입니다.random BSD 스펙 함수입니다.

차이 randrandomrandom훨씬 사용될 32 비트 난수 되돌아가, rand통상 16 비트의 수를 반환한다. BSD 맨 페이지에서는 하위 비트 rand가 주기적이며 예측 가능하므로 rand적은 수의 사용자에게는 쓸모가 없습니다.


3
@ Neil-지금까지 모든 답변에 STL이 언급되었으므로 질문이 불필요한 참조를 제거하기 위해 신속하게 편집되었다고 생각합니다.
Michael Burr

rand ()는 작은 숫자에는 쓸모가 없습니다. 비트 쉬프트하고 실제로 필요한 경우 임의의 높은 비트 만 사용할 수 있습니다.
Chris Lutz가

@Chris, 난수의 크기를 알면 가능하지만 런타임 중에 난수의 필요한 크기가 변경되면 (예 : 동적 배열 섞기 등) 이러한 경고를 해결하기가 어려울 수 있습니다.
dreamlax

여기에서 임의의 함수를 찾을 수 없습니다 :-(
kasia.b

해당 링크의 @ kasia.b에는 extern int rand(void);및이 extern void srand(unsigned int);있습니다.
RastaJedi

7

ISAAC (Indirection, Shift, Accumulate, Add 및 Count)를 살펴보십시오 . 균일하게 분포되어 있으며 평균주기 길이는 2 ^ 8295입니다.


2
ISAAC는 속도 때문에 흥미로운 RNG이지만 아직 심각한 암호화 관심을받지 못했습니다.
user2398029

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(). 참고 ( 매우 중요 ) : 랜드 기능의 시드를 설정하십시오. 그렇지 않으면 임의의 숫자가 실제로 임의아닙니다 . 이것은 매우 중요합니다. 고맙게도 일반적으로 시스템 틱 타이머와 날짜의 조합을 사용하여 좋은 씨앗을 얻을 수 있습니다.


6
두 점 a) 발생기의 씨드 방법에 관계없이 난수는 "진정한"난수가 아닙니다. 그리고 b) 예를 들어 테스트를 위해 의사 랜덤 시퀀스가 ​​많은 상황에서 항상 동일하도록하는 것이 매우 편리합니다.

16
숫자가 정말로 임의 인 것이 매우 중요하다면, rand () 함수를 사용해서는 안됩니다.
tylerl

1
rand의 값은 시드를 설정했는지 여부에 관계없이 전혀 "정말"임의의 것이 아닙니다. 알려진 시드가 주어지면 시퀀스를 예측할 수 있습니다. "정말"난수 생성이 어렵습니다. 랜드와 관련된 엔트로피는 없습니다.
dreamlax

2
물론 그들은-발전기가 라이브러리에 의해 시드됩니다 (아마도 0이지만 유효한 시드입니다).

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
srand (rand ())를 추가해도이 프로그램이 1 초 이내에 여러 번 실행되는 경우 시퀀스의 무작위성이 증가하지 않습니다. time (NULL)은 여전히 ​​각각에 대해 동일한 값을 반환하고 첫 번째 rand ()는 동일하게 긴 값을 반환하며 srand ()에 대한 두 번째 호출은 동일한 값을 가지므로 여전히 동일한 임의 순서를 갖습니다. argc의 주소를 사용하면 프로그램이 실행될 때마다이 주소가 다를 것이 보장되는 경우에만 도움이 될 수 있습니다. 항상 그런 것은 아닙니다.
theferrit32

3

글쎄, STL은 C가 아니라 C ++이므로 원하는 것을 모른다. 그러나 C를 원하면 rand()and srand()함수가 있습니다.

int rand(void);

void srand(unsigned seed);

이것들은 모두 ANSI C의 일부입니다. random()기능 도 있습니다 :

long random(void);

그러나 내가 알 수있는 한 random()표준 ANSI C는 아닙니다. 타사 라이브러리는 나쁜 생각은 아니지만 모든 숫자를 실제로 생성 해야하는 숫자에 따라 다릅니다.


3

9에서 50 사이의 난수를 생성하는 C 프로그램

#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되지 BETWEEN 언급 무엇의
Shivam K. Thakkar

2
모듈로 작업에 편향이 발생했습니다.
jww

2

rand() 난수를 생성하는 가장 편리한 방법입니다.

random.org와 같은 온라인 서비스에서 임의의 숫자를 잡을 수도 있습니다.


1
C에 이식 가능하고 효율적인 방법을 포함 시키면 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
무하마드 사 디크에게

그 의견을 말했을 때 나는 보편적 인 편집 권한이 없었으며 일반적으로 실제 답변을 변경 한 코드 변경은 거부됩니다. 대답을 고치지 않아도 괜찮습니다.
b4hand

고유 값의 임의 순열을 생성하려는 의도라면이 코드에는 여전히 버그가 있습니다. 값 84를 두 번 생성하고 값 48을 생성하지 않습니다. 또한 난수 생성기를 시드하지 않으므로 모든 실행에서 시퀀스가 ​​동일합니다.
b4hand

1
변수 a와 b는이 코드에 정의되어 있습니다. 오류가 없습니다. 구문과 논리 오류도 없습니다.
Muhammad Sadiq 2016 년

잘못되었습니다. 언급 한대로 이미 출력을 직접 확인했습니다.
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 ()는 플랫폼마다 다릅니다. GNU / Linux의 rand () 값은 BSD 또는 Windows의 값보다 낫습니다.
George Koehler

이것은 무작위성을 테스트하는 올바른 방법이 아닙니다.
Veedrac

목적과 위협 / 위험 모델에 따라 다릅니다. 암호화 적으로 강력한 RNG의 경우 RDRAND (또는 RDSEED)를 사용하십시오. 카지노 레벨이 아닌 단순한 주사위 던지기의 경우 위의 것으로 충분합니다. 키워드는 " 충분히 좋습니다 ".
마우스

0

최근 응용 프로그램에서 의사 난수 생성기에 심각한 문제가 발생했습니다. pyhton 스크립트를 통해 C 프로그램을 반복적으로 호출했으며 다음 코드를 시드로 사용했습니다.

srand(time(NULL))

그러나 이후로 :

  • rand는 동일한 의사 난수 시퀀스를 생성하여 srand에 동일한 시드를 제공합니다 (참조 man srand).
  • 이미 언급했듯이 시간 함수는 초에서 초로 만 변경됩니다. 응용 프로그램이 동일한 초 내에 여러 번 실행되면 time매번 동일한 값을 반환합니다.

내 프로그램은 동일한 순서의 숫자를 생성했습니다. 이 문제를 해결하기 위해 3 가지 작업을 수행 할 수 있습니다.

  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

rand()암호화 데이터에 사용해서는 안됩니다. 적어도 내 응용 프로그램에는 암호화 데이터가 포함되어 있지 않으므로 주어진 방법으로 문제가 없습니다.
Koldar

0

rand()여기에 모든 사람들의 제안에도 불구하고 , 당신은 당신이하지 않으면 사용하고 싶지 않습니다 rand()! 그 난수rand()생성 는 종종 매우 나쁩니다. Linux 매뉴얼 페이지에서 인용하려면 :

Linux C 라이브러리 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입니다. 1 년 전에 업데이트를받은 (IEEE Std 1003.1-2008) (IEEE Std 1003.1-2008, 2016 Edition). 그래서 나는 random()매우 이식성 이 있다고 생각 합니다.

POSIX.1-2001도를 도입 lrand48()mrand48()기능은 여기를 참조 :

이 함수 계열은 선형 합동 알고리즘과 48 비트 정수 산술을 사용하여 의사 난수를 생성해야합니다.

그리고 꽤 좋은 의사 랜덤 소스는 arc4random()많은 시스템에서 사용할 수 있는 기능입니다. 1997 년경 BSD에 공식 표준의 일부는 아니지만 Linux 및 macOS / iOS와 같은 시스템에서 찾을 수 있습니다.


random()Windows에는 존재하지 않습니다.
Björn Lindqvist

@ BjörnLindqvist Windows도 POSIX 시스템이 아닙니다. 그것은 적어도 기본 POSIX API를 지원하지 않는 시장에서 유일하게 시스템입니다 (iOS와 같은 잠겨있는 시스템조차도 지원합니다). Windows는 rand()C 표준에서 요구하는 대로만 지원 합니다. 다른 모든 경우에는 평소와 같이 Windows 전용 특수 솔루션이 필요합니다. #ifdef _WIN32는 Windows를 지원하려는 크로스 플랫폼 코드에서 가장 자주 볼 수있는 문구이며 일반적으로 모든 시스템에서 작동하는 솔루션 하나와 Windows에만 필요한 솔루션이 있습니다.
Mecki

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()일반적으로는의 값 반환 같은 "임의"값을 반환합니다 빠른 속도로이 함수를 호출합니다.
Blastfurnace

3
이 함수는 유닉스 random()함수 와 혼동 될 것 입니다.
George Koehler
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.