랜덤연산자 중복관련질문

tkrl2246의 이미지

이 코드에서 중복된 숫자가 랜덤으로 걸리는걸 없애보려고합니다...ㅎㅎ...
어떻게 해야할가요.
그리고 이출력값을 배열에 저장하려면 어떻게 해야할까요?..ㅎㅎ

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
 
int num(int n1, int n2);
void main() {
	srand(GetTickCount());
 
	int i;
 
	for (i = 0; i < 10; i++) {
		printf("%d\n", num(1, 100));
 
		}
	}
 
 
	int num(int n1, int n2) {
		return (int)( rand() % 100)+1;
	}
pynoos의 이미지

랜덤의 문제에 있어선 중복을 해결하기 위해서 이미 나온 것이라면 다시 시행하는 방식으로 할 수 있겠지만, 다른 방법으로는 나올 수 있는 모든 경우의 수를 배열 한 뒤 순서를 섞은뒤 하나씩 빼는 방법도 있습니다.

위의 예라면, 100개에 대한 배열을 1, 100까지 증가시켜가면서 채우고, qsort를 수행합니다. 수행할 때 비교하는 함수는

int compare( void * a, void * b )
{
return rand() % 3 - 1;
}

정도로 하면 되지 않을까 싶습니다. 즉 비교를 횡설수설하게해서 섞는 것이지요.

그리고 위의 경우라면 배열의 앞 10개를 출력하면 될 것 같네요.

 의 이미지

C언어 라이브러리 rand()에 의존하여 randomness가 정말로 중요한 어플리케이션을 작성하는 것은 불가피하지 않다면 별로 좋은 생각이 아닙니다.
일단
(1)randomness 퀄리티 보장이 없고
(2)불편해요.

이웃 동네...라고 하기는 요즘 좀 많이 멀어진 C++ 동네에서는 C++11부터 빵빵하게 지원해 주기 시작한 것과 대조적이죠.
http://en.cppreference.com/w/cpp/numeric/random 참조.

pynoos님의 방식대로 처음부터 다 섞어놓고 시작하는 방식도 있습니다만,
(1) 100개의 숫자 중 10개밖에 안 뽑을 건데 전부 뒤섞을 필요가 있을까요.
뭐 이 문제는 사실 요즘 컴퓨터에서 이 정도 추가 작업은 별로 거슬릴 정도는 아니라고 쳐도...

(2) qsort()를 그런 식으로 썼을 때 과연 정말 고르게 뒤섞일지 확신할 수가 없습니다.
사실 C++03 정도만 됐어도 random_shuffle(http://en.cppreference.com/w/cpp/algorithm/random_shuffle)을 쓰면 되는데, C언어에서 그게 제공되지 않는다고 해도 qsort()를 그런 식으로 남용하는 게 정당화되지는 않습니다. 이와 관련된 주제의 질문이 stack overflow에 올라왔었으니 참고 바랍니다.

http://stackoverflow.com/questions/790083/does-qsort-demand-consistent-comparisons-or-can-i-use-it-for-shuffling

어쨌거나 질문자님께서 바라는 코드를 rand()만으로 가장 간편하게 짜기 위해서는 위 링크에서의 여러 답변자들이 제안하는 Fisher–Yates shuffle 알고리즘을 사용하는 게 좋아 보이는군요. 게다가 이 알고리즘은 결과를 앞에서부터 차례차례 생성하도록 구현할 수 있으니 더할 나위 없지요.

https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

구현하는 데 문제가 하나 있다면, 임의 크기의 정수 집합에서 균일한 확률로 정수 하나를 뽑는 함수를 만드는 것이죠. 확률을 정말로 균일하게 만들기가 꽤 까다롭습니다. 아래의 random_range()와 같이 최대한 노력해 봤습니다만 슬프게도 여전히 완벽하지는 않습니다.

(1) 별로 견고한 코드는 아닙니다. 동일한 state 객체를 가지고 trial()NR_CANDIDATE회 초과하여 호출하면 무슨 일이 생길지 장담할 수 없다는 말씀입니다.
(2) 앞서 말씀드렸듯 random_range()엄밀히 말하면 범위 안의 정수를 균일한 확률로 생성하지 못합니다. 미세한 확률 차이가 생기는데, 왜 그런지는 직접 생각해 보세요. 어쨌든 저는 최선을 다했습니다. 사실 어차피 미묘한 차이라 그냥 naive한 구현을 쓰는 사람도 많아요.
(3) 질문자님이 출력을 배열에 저장하는 방법도 질문하시길래 main()에서 배열에 한 번 담았다가 출력시켰습니다.
(4) 저는 지금 윈도우즈에서 사용 가능한 컴파일러가 없기 때문에 #include <Windows.h>srand(GetTickCount()); 부분은 리눅스에서 컴파일 가능한 코드로 대체하여 작성하고 테스트했습니다. 그러니 그 부분에서 컴파일 문제가 생기더라도 양해해 주시길.
(5) randomness가 들어가는 프로그래밍은 까다로워요. 다른 고수 분들의 답변도 기대하겠습니다.

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
 
#define NR_CANDIDATE 100
 
struct state_t{
    unsigned int nr_trial;
    unsigned int candidates[NR_CANDIDATE];
};
 
static void init_state(struct state_t *);
static unsigned int trial(struct state_t *);
static unsigned int random_range(unsigned int, unsigned int);
 
int main(void){
    unsigned int i;
    unsigned int random_number[10];
    struct state_t state;
    srand(GetTickCount());
    init_state(&state);
    for(i=0;i<10;i++){
        random_number[i] = trial(&state);
    }
    for(i=0;i<10;i++){
        printf("%u\n", random_number[i]);
    }
    return 0;
}
 
void init_state(struct state_t *state){
    unsigned int i;
    state->nr_trial = 0;
    for(i=0;i<NR_CANDIDATE;i++){
        state->candidates[i] = i+1;
    }
}
 
unsigned int trial(struct state_t *state){
    unsigned int ret_index = random_range(state->nr_trial, NR_CANDIDATE);
    unsigned int ret = state->candidates[ret_index];
    state->candidates[ret_index] = state->candidates[state->nr_trial];
    state->candidates[state->nr_trial] = ret;
    state->nr_trial++;
    return ret;
}
 
unsigned int random_range(unsigned int begin, unsigned int end){
    unsigned int range_size = end - begin;
    return ((unsigned int)((rand() / (((double)RAND_MAX) + 1)) * range_size)) + begin;
}
shint의 이미지

범위'를 지정하면. 중복이 안되죠. ㅇ_ㅇ''

대충 만드느라. 코드가 정확하지는 않을 수 있습니다.

#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
 
int num(int n1);
 
void main() 
{
	srand(GetTickCount());
 
	int i;
	int k=1;
	for (i = 1; i < 10; i++) 
	{
		printf("k:%2d i*10:%d\t", k, i*10);
		printf("%2d\n", num(k));
		k = i * 10 +1;
 
	}
}
 
 
int num(int n1) 
{
	int r = rand() % 9 + 1;
	r = r + n1;
	return r;
}
 
 
 
	k :  1 i * 10 : 10     3
	k : 11 i * 10 : 20    17
	k : 21 i * 10 : 30    30
	k : 31 i * 10 : 40    37
	k : 41 i * 10 : 50    44
	k : 51 i * 10 : 60    60
	k : 61 i * 10 : 70    63
	k : 71 i * 10 : 80    77
	k : 81 i * 10 : 90    82
	Press any key to continue . . .

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.