범위 내에서 임의의 정수를 생성하는 방법


108

이것은 이전에 게시 된 질문의 후속입니다.

C에서 난수를 생성하는 방법은 무엇입니까?

주사위의 측면을 모방하기 위해 1 ~ 6과 같은 특정 범위 내에서 임의의 숫자를 생성 할 수 있기를 바랍니다.

어떻게하면 되나요?


3
당신이 언급 한 질문의 두 번째 답을 보면 답이 있습니다. rand () % 6.
Mats Fredriksson

2
나는 그것이 어떻게 작동하는지 이해하지 못했기 때문에 명확성을 위해 별도의 질문을하기로 결정했습니다.
Jamie Keeling

2
임의의 생각 : 프로그래머의 임의의 단면을 폴링하면 임의의 숫자가 무작위로 숫자를 생성하는 방법을 임의로 생각하고 있음을 알 수 있습니다. 우주가 정확하고 예측 가능한 법칙의 지배를 받는다는 점을 고려할 때, 우리가 더 무작위로 생성하려고하는 것이 흥미롭지 않습니까? 이와 같은 질문은 항상 10,000 개 이상의 포스터를 가져 오는 경향이 있습니다.
Armstrongest

2
@Mats rand () % 6은 0을 반환 할 수 있습니다. 주사위에는 좋지 않습니다.
new123456 2011 년

stackoverflow.com/a/6852396/419 를 링크하는 답변 대신 수락 된 답변으로 표시 할 수 있습니까? :) 감사합니다.
Kev

답변:


173

지금까지의 모든 답은 수학적으로 잘못되었습니다. 반환 하는 구간의 길이를 나누지 않는 한 (즉, 2의 거듭 제곱) 반환 rand() % N은 범위 내의 숫자를 균일하게 제공하지 않습니다 . 또한의 모듈 리가 독립적 인지 여부를 알지 못합니다. 균일하지만 매우 무작위 적이 지 않은. 합리적으로 보이는 유일한 가정 은 포아송 분포를내는 것입니다. 같은 크기의 겹치지 않는 두 부분 구간은 똑같이 가능성이 있고 독립적입니다. 유한 한 값 집합의 경우 이는 균일 한 분포를 의미하며의 값 이 잘 분산되도록합니다.[0, N)Nrand()rand()0, 1, 2, ...rand()rand()

즉, 범위를 변경하는 유일한 올바른 방법은 rand()상자로 나누는 것입니다. 예를 들어 RAND_MAX == 11범위를 원하는 경우 1, 2 등으로 1..6할당해야합니다 . 이들은 분리되고 동일한 크기의 간격이므로 균일하고 독립적으로 분포됩니다.{0,1}{2,3}

부동 소수점 나누기를 사용하라는 제안은 수학적으로 타당하지만 원칙적으로 반올림 문제가 있습니다. 아마도 double그것을 작동시키기에 충분히 높은 정밀도 일 것입니다. 아마 아닐거야. 나는 모르고 그것을 알아 내고 싶지도 않다. 어쨌든 대답은 시스템에 따라 다릅니다.

올바른 방법은 정수 산술을 사용하는 것입니다. 즉, 다음과 같은 것을 원합니다.

#include <stdlib.h> // For random(), RAND_MAX

// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
  unsigned long
    // max <= RAND_MAX < ULONG_MAX, so this is okay.
    num_bins = (unsigned long) max + 1,
    num_rand = (unsigned long) RAND_MAX + 1,
    bin_size = num_rand / num_bins,
    defect   = num_rand % num_bins;

  long x;
  do {
   x = random();
  }
  // This is carefully written not to overflow
  while (num_rand - defect <= (unsigned long)x);

  // Truncated division is intentional
  return x/bin_size;
}

루프는 완벽하게 균일 한 분포를 얻기 위해 필요합니다. 예를 들어, 0에서 2까지의 임의의 숫자가 주어지고 0에서 1까지의 숫자 만 원하면 2를 얻지 못할 때까지 계속 당기십시오. 이것이 동일한 확률로 0 또는 1을 제공하는지 확인하는 것은 어렵지 않습니다. 이 방법은 다르게 코딩되었지만 nos가 대답 한 링크에도 설명되어 있습니다. 나는 더 나은 배포판을 가지고 random()있기보다는 rand()(에 대한 man 페이지에서 언급했듯이 rand()) 사용하고 있습니다.

기본 범위를 벗어난 임의의 값을 얻으려면 [0, RAND_MAX]까다로운 작업을 수행해야합니다. 아마도 가장 편리한 함수를 정의하는 것입니다 random_extended()끌어 n비트 (사용 random_at_most()으로) 되돌아 [0, 2**n)한 다음 적용 random_at_most()random_extended()대신에 random()(그리고 2**n - 1대신에 RAND_MAX) 이하의 임의의 값을 뽑아 2**n당신이 그런를 보유 할 수있는 숫자 유형이 가정, 가치. 마지막으로, 물론 음수 값을 포함 [min, max]하여를 사용하여 값을 얻을 수 있습니다 min + random_at_most(max - min).


1
@Adam Rosenfield, @ Ryan Reich : Adam이 답변 한 관련 질문에서 : stackoverflow.com/questions/137783/… 가장 많이 찬성 된 답변 : '모듈러스'의 사용법은 올바르지 않습니다. 1..21에서 1..7을 생성하려면 Ryan이 설명한 절차를 사용해야합니다. 내가 틀 렸으면 수정 해주세요.
Arvind

1
추가 검토에서 여기서 또 다른 문제는 이것이 작동하지 않는다는 것입니다 max - min > RAND_MAX. 이는 위에서 언급 한 문제보다 더 심각한 문제입니다 (예 : VC ++에는 RAND_MAX32767 만 있음).
interjay

2
while 루프를 더 읽기 쉽게 만들 수 있습니다. 조건부에서 할당을 수행하는 대신 do {} while().
theJPster dec

4
이봐,이 답변은 혜성 OS 책에서 인용) 처음으로 내가 가르치는 책에서 것을 볼
vpuente

3
그것은 또한 OSTEP 책 :)에 인용 pages.cs.wisc.edu/~remzi/OSTEP (4 장 9 페이지)
rafascar

33

@Ryan Reich의 답변에 이어 정리 된 버전을 제공 할 것이라고 생각했습니다. 첫 번째 경계 검사는 두 번째 경계 검사를 고려할 때 필요하지 않으며 재귀 적이 아닌 반복적으로 만들었습니다. [최소, 최대] 범위의 값을 반환합니다 . 여기서 max >= min1+max-min < RAND_MAX.

unsigned int rand_interval(unsigned int min, unsigned int max)
{
    int r;
    const unsigned int range = 1 + max - min;
    const unsigned int buckets = RAND_MAX / range;
    const unsigned int limit = buckets * range;

    /* Create equal size buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    do
    {
        r = rand();
    } while (r >= limit);

    return min + (r / buckets);
}

28
범위> = RAND_MAX 인 경우 무한 루프에 멈 춥니 다. 내가 아는 방법을 올려주세요 : /
theJPster

24
어떻게 알아!?
Fantastic Mr Fox

1
int를 unsigned int (r> = limit)와 비교하고 있습니다. 문제는 < 및 <= 이후 limitint (및 선택적으로 bucket도) 를 만들어 쉽게 해결됩니다 . 수정 : 제안서를 제출하고 수정했습니다. RAND_MAX / rangeINT_MAXbuckets * rangeRAND_MAX
rrrrrrrrrrrrrrrr

@Ryan 제국의 솔루션은 여전히 나를 더 잘 제공 (이하 바이어스) 유통
블라디미르

20

다음은 범위의 최대 값과 최소값을 알고 있고 범위 사이에 포함 된 숫자를 생성하려는 경우 공식입니다.

r = (rand() % (max + 1 - min)) + min

9
Ryan의 답변에서 언급했듯이 이것은 편향된 결과를 생성합니다.
David Wolever 2014-07-10

6
바이어스 결과, 잠재적 int으로 오버 플로우 max+1-min.
chux-Monica 복원

1
이것은 정수 최소 및 최대에서만 작동합니다. 최소 및 최대 플로트 경우, 그것은 %의 작업을 수행 할 수 없습니다
Taioli 프란체스코

17
unsigned int
randr(unsigned int min, unsigned int max)
{
       double scaled = (double)rand()/RAND_MAX;

       return (max - min +1)*scaled + min;
}

다른 옵션 은 여기 를 참조 하십시오 .


2
@ S.Lott-정말 아닙니다. 각각은 약간 더 높은 배당률 사례를 다르게 배포합니다. 이중 수학은 거기에 더 많은 정밀도가 있다는 인상을 주지만 쉽게 사용 (((max-min+1)*rand())/RAND_MAX)+min하고 아마도 정확히 동일한 분포를 얻을 수 있습니다 (RAND_MAX가 int에 비해 오버플로되지 않을 정도로 충분히 작다고 가정).
Steve314 2010 년

4
이것은 약간 위험하다 : 그것은 (매우 드물게) 반환이 가능의 max + 1경우 중 하나, rand() == RAND_MAX또는 rand()매우 가까이 RAND_MAX와 부동 소수점 오류는 최종 결과 과거를 밀어 max + 1. 안전을 위해 결과를 반환하기 전에 결과가 범위 내에 있는지 확인해야합니다.
Mark Dickinson

1
@Christoph : 동의합니다 RAND_MAX + 1.0. 나는 확실하지의 좋은의 정도는 방지 할 수 있다는 여전히 해요 max + 1특히 :하지만, 수익을 + min마지막에 생산 끝낼 수 있었다 라운드 포함 max + 1랜드의 큰 값 ()에 대한합니다. 이 접근 방식을 완전히 포기하고 정수 산술을 사용하는 것이 더 안전합니다.
Mark Dickinson

3
Christoph가 제안한대로 RAND_MAX가 대체 되면 정수 산술을 사용하여 수행 RAND_MAX+1.0되는 경우 안전하다고 생각합니다 .. (분명하지 않은) 이유는 IEEE 754 산술과 반올림을 가정하고 (또한 정확히 double로 표현할 수 있지만 일반적인 시스템에서는 사실입니다) 항상 사실입니다 . 모든 양의 double 및 모든 double 만족 . + minreturn (unsigned int)((max - min + 1) * scaled) + minmax - min + 1x * scaled < xxscaled0.0 <= scaled && scaled < 1.0
Mark Dickinson

1
실패 randr(0, UINT_MAX): 항상 0을 생성합니다.
chux-Monica 복원 dec

12

그냥하지 않겠습니까?

srand(time(NULL));
int r = ( rand() % 6 ) + 1;

%모듈러스 연산자입니다. 기본적으로 6으로 나누고 나머지를 반환합니다 ... from 0-5


1
1-6의 결과를 제공합니다. 이것이 바로 + 1의 의미입니다.
Armstrongest

4
Simon, rand()생성기 상태의 하위 비트 (LCG를 사용하는 경우)를 포함하는 모든 곳에서 사용중인 libc를 보여줍니다 . 지금까지 하나도 보지 못했습니다. 모두 (예, RAND_MAX가 32767 인 MSVC를 포함하여) 하위 비트를 제거 합니다. 모듈러스를 사용하는 것은 다른 이유로 권장되지 않습니다. 즉, 더 작은 숫자를 선호하는 분포를 왜곡하기 때문입니다.
Joey

@Johannes : 슬롯 머신이 모듈러스를 사용하지 않는다고 말하는 것이 안전합니까?
Armstrongest

0은 어떻게 제외합니까? 30의 루프에서 실행하면 두 번째 또는 세 번째로 실행하면 대략 절반 정도의 0이있는 것 같습니다. 이것은 일종의 우연입니까?
Jamie Keeling

@Johannes : 아마도 요즘에는 그다지 문제가되지 않지만 전통적으로 하위 비트를 사용하는 것은 바람직하지 않습니다. c-faq.com/lib/randrange.html
jamesdlin

9

편향 문제를 이해하고 있지만 거부 기반 방법의 예측할 수없는 런타임을 견딜 수없는 사람들을 위해이 시리즈는 [0, n-1]간격 에서 점차적으로 편향된 임의의 정수를 생성 합니다.

r = n / 2;
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
r = (rand() * n + r) / (RAND_MAX + 1);
...

고정 소수점 임의의 i * log_2(RAND_MAX + 1)비트 수 ( i반복 횟수) 를 합성하고에 의해 긴 곱셈을 수행하여이를 수행합니다 n.

에 비해 비트 수가 충분히 크면 n바이어스가 헤아릴 수 없을 정도로 작아집니다.

이 질문 에서와 같이 RAND_MAX + 1이보다 작은 지 n( 이 질문 에서와 같이 ) 또는 2의 거듭 제곱 아닌지 여부 는 중요하지 않지만 RAND_MAX * n큰 경우 정수 오버플로를 방지하려면주의해야합니다 .


2
RAND_MAX는 자주 INT_MAX이므로 RAND_MAX + 1-> UB (예 : INT_MIN)
chux-Monica 복원

@chux는 "정수 오버플로 RAND_MAX * n가 크면 주의해야합니다"라는 의미 입니다. 요구 사항에 적합한 유형을 사용하도록 준비해야합니다.
sh1 dec.

@chux " RAND_MAX는 종종 INT_MAX"예,하지만 16 비트 시스템에서만 가능합니다! 합리적으로 현대적인 건축물은 INT_MAX2 ^ 32 / 2와 RAND_MAX2 ^ 16 / 2에 놓이게 될 것 입니다. 이것은 잘못된 가정입니까?
cat

2
@cat 오늘 2 개의 32 비트 int컴파일러를 테스트했으며 , RAND_MAX == 32767하나와 RAND_MAX == 2147483647다른 컴파일러를 찾았 습니다 . 내 전반적인 경험 (수십 년)은 RAND_MAX == INT_MAX더 자주 있습니다. 따라서 합리적으로 현대적인 32 비트 아키텍처가 확실히 RAND_MAXat 2^16 / 2. C 스펙이 허용하기 때문에 32767 <= RAND_MAX <= INT_MAX나는 경향이 아니라 어쨌든 그것을 코딩합니다.
chux-Monica 복원

3
여전히 "정수 오버플로를 방지하려면주의해야합니다."
sh1

4

모듈로 편향을 피하기 위해 (다른 답변에서 제 안됨) 항상 다음을 사용할 수 있습니다.

arc4random_uniform(MAX-MIN)+MIN

여기서 "MAX"는 상한이고 "MIN"은 하한입니다. 예를 들어 10에서 20 사이의 숫자의 경우 :

arc4random_uniform(20-10)+10

arc4random_uniform(10)+10

간단한 솔루션이며 "rand () % N"을 사용하는 것보다 낫습니다.


1
우후, 이것은 다른 답변보다 수십억 배나 낫습니다. #include <bsd/stdlib.h>먼저 해야 할 일이 있습니다. 또한 MinGW 또는 CygWin없이 Windows에서 이것을 얻는 방법에 대한 아이디어가 있습니까?
cat

1
아니요, 다른 답변이 더 일반적이기 때문에 다른 답변보다 그 자체로 낫지는 않습니다. 여기에서는 arc4random으로 제한되고 다른 답변을 사용하면 다른 임의 소스를 선택하고 다른 숫자 유형으로 작업 할 수 있으며 마지막으로 문제를 이해하는 데 도움이 될 수 있습니다. 문제는, 그럼에도 불구하고 ... 어떤 특별한 요구 사항 또는 arc4random에 액세스 할 수있는 다른 사람들을위한 흥미로운 것을 잊지 마십시오 경우 당신이 그것을에 액세스 할 수 있으며 빠른 솔루션을 원하는, 그것은 😊 참으로 아주 좋은 답변입니다
K. BIERMANN

4

다음은 Ryan Reich의 솔루션보다 약간 더 간단한 알고리즘입니다.

/// Begin and end are *inclusive*; => [begin, end]
uint32_t getRandInterval(uint32_t begin, uint32_t end) {
    uint32_t range = (end - begin) + 1;
    uint32_t limit = ((uint64_t)RAND_MAX + 1) - (((uint64_t)RAND_MAX + 1) % range);

    /* Imagine range-sized buckets all in a row, then fire randomly towards
     * the buckets until you land in one of them. All buckets are equally
     * likely. If you land off the end of the line of buckets, try again. */
    uint32_t randVal = rand();
    while (randVal >= limit) randVal = rand();

    /// Return the position you hit in the bucket + begin as random number
    return (randVal % range) + begin;
}

Example (RAND_MAX := 16, begin := 2, end := 7)
    => range := 6  (1 + end - begin)
    => limit := 12 (RAND_MAX + 1) - ((RAND_MAX + 1) % range)

The limit is always a multiple of the range,
so we can split it into range-sized buckets:
    Possible-rand-output: 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16
    Buckets:             [0, 1, 2, 3, 4, 5][0, 1, 2, 3, 4, 5][X, X, X, X, X]
    Buckets + begin:     [2, 3, 4, 5, 6, 7][2, 3, 4, 5, 6, 7][X, X, X, X, X]

1st call to rand() => 13
     13 is not in the bucket-range anymore (>= limit), while-condition is true
         retry...
2nd call to rand() => 7
     7 is in the bucket-range (< limit), while-condition is false
         Get the corresponding bucket-value 1 (randVal % range) and add begin
    => 3

1
RAND_MAX + 1int추가 를 쉽게 넘칠 수 있습니다 . 이 경우 (RAND_MAX + 1) % range의심스러운 결과가 생성됩니다. 고려(RAND_MAX + (uint32_t)1)
chux-Monica 복원

2

Ryan이 맞지만 무작위성의 원인에 대해 알려진 것을 기반으로 솔루션은 훨씬 더 간단 할 수 있습니다. 문제를 다시 설명하려면 :

  • [0, MAX)균등 분포 로 범위 내에서 정수를 출력하는 임의성의 근원이 있습니다 .
  • 목표는 범위 [rmin, rmax]에서 균일하게 분포 된 임의의 정수를 생성하는 것입니다 0 <= rmin < rmax < MAX.

빈 (또는 "박스")의 수는 원래 숫자의 범위보다 훨씬 작은 경우 내 경험에, 그리고 원본 소스 강력한 암호입니다 - 모든 rigamarole을 통과 할 필요가없고, 간단한 모듈 부문 것 충분하고 (예 : output = rnd.next() % (rmax+1), if rmin == 0), 속도 손실없이 "충분히"균일하게 분포 된 난수를 생성합니다. 핵심 요소는 임의성 소스입니다 (예 : 어린이, 집에서를 사용하지 마십시오 rand()).

실제 작동 방식에 대한 예제 / 증명입니다. 나는 임의의 바이트 (Intel RDRAND 기반)를 생성하는 강력한 암호화 소스를 사용하여 1에서 22까지의 난수를 생성하고 싶었습니다. 결과는 다음과 같습니다.

Rnd distribution test (22 boxes, numbers of entries in each box):     
 1: 409443    4.55%
 2: 408736    4.54%
 3: 408557    4.54%
 4: 409125    4.55%
 5: 408812    4.54%
 6: 409418    4.55%
 7: 408365    4.54%
 8: 407992    4.53%
 9: 409262    4.55%
10: 408112    4.53%
11: 409995    4.56%
12: 409810    4.55%
13: 409638    4.55%
14: 408905    4.54%
15: 408484    4.54%
16: 408211    4.54%
17: 409773    4.55%
18: 409597    4.55%
19: 409727    4.55%
20: 409062    4.55%
21: 409634    4.55%
22: 409342    4.55%   
total: 100.00%

나는 공정한 주사위 같은 차 세계 대전 암호 기계 강력하게 암호화 코드북 생성 던져 (내 목적을 위해 필요로하는이 균일에 가까운입니다 http://users.telenet.be/d.rijmenants/en/kl-7sim.htm 등 ). 출력은 눈에 띄는 편향을 보이지 않습니다.

암호화가 강력한 (진정한) 난수 생성기의 소스는 인텔 디지털 난수 생성기 와 64 비트 (부호없는) 난수를 생성하는 샘플 코드입니다.

int rdrand64_step(unsigned long long int *therand)
{
  unsigned long long int foo;
  int cf_error_status;

  asm("rdrand %%rax; \
        mov $1,%%edx; \
        cmovae %%rax,%%rdx; \
        mov %%edx,%1; \
        mov %%rax, %0;":"=r"(foo),"=r"(cf_error_status)::"%rax","%rdx");
        *therand = foo;
  return cf_error_status;
}

나는 Mac OS X에서 clang-6.0.1 (스트레이트)을 사용하고 gcc-4.8.3에서 "-Wa, q"플래그를 사용하여 컴파일했습니다 (GAS는 이러한 새로운 명령을 지원하지 않기 때문입니다).


gcc randu.c -o randu -Wa,q(Ubuntu 16의 GCC 5.3.1) 또는 clang randu.c -o randu(Clang 3.8.0)으로 컴파일 되지만 런타임에 Illegal instruction (core dumped). 어떤 아이디어?
cat

첫째, CPU가 실제로 RDRAND 명령을 지원하는지 여부를 알 수 없습니다. 귀하의 OS는 상당히 최신이지만 CPU는 그렇지 않을 수 있습니다. 둘째 (하지만 가능성은 낮음)-우분투에 어떤 종류의 어셈블러가 포함되어 있는지 모르겠습니다 (우분투는 패키지를 업데이트하는 것이 상당히 역방향 인 경향이 있습니다). CPU가 RDRAND를 지원하는지 테스트하는 방법에 대해서는 내가 언급 한 Intel 사이트를 확인하십시오.
마우스

정말 좋은 점이 있습니다. 여전히 얻을 수없는 것은 무엇이 그렇게 잘못되었는지입니다 rand(). 몇 가지 테스트를 시도 하고이 질문을 게시 했지만 아직 확실한 답을 찾을 수 없습니다.
myradio

1

앞서 말했듯이 모듈로는 분포를 왜곡하기 때문에 충분하지 않습니다. 다음은 비트를 마스킹하고 배포가 왜곡되지 않도록 사용하는 코드입니다.

static uint32_t randomInRange(uint32_t a,uint32_t b) {
    uint32_t v;
    uint32_t range;
    uint32_t upper;
    uint32_t lower;
    uint32_t mask;

    if(a == b) {
        return a;
    }

    if(a > b) {
        upper = a;
        lower = b;
    } else {
        upper = b;
        lower = a; 
    }

    range = upper - lower;

    mask = 0;
    //XXX calculate range with log and mask? nah, too lazy :).
    while(1) {
        if(mask >= range) {
            break;
        }
        mask = (mask << 1) | 1;
    }


    while(1) {
        v = rand() & mask;
        if(v <= range) {
            return lower + v;
        }
    }

}

다음의 간단한 코드를 통해 배포판을 볼 수 있습니다.

int main() {

    unsigned long long int i;


    unsigned int n = 10;
    unsigned int numbers[n];


    for (i = 0; i < n; i++) {
        numbers[i] = 0;
    }

    for (i = 0 ; i < 10000000 ; i++){
        uint32_t rand = random_in_range(0,n - 1);
        if(rand >= n){
            printf("bug: rand out of range %u\n",(unsigned int)rand);
            return 1;
        }
        numbers[rand] += 1;
    }

    for(i = 0; i < n; i++) {
        printf("%u: %u\n",i,numbers[i]);
    }

}

rand ()에서 숫자를 거부하면 매우 비효율적입니다. 이것은 범위가 2 ^ k + 1로 쓸 수있는 크기 일 때 특히 비효율적입니다. 그러면 느린 rand () 호출에서 시도한 모든 시도의 거의 절반이 조건에 의해 거부됩니다. RAND_MAX 모듈로 범위를 계산하는 것이 더 나을 수도 있습니다. 좋아요 : v = rand(); if (v > RAND_MAX - (RAND_MAX % range) -> reject and try again; else return v % range;모듈로가 마스킹보다 훨씬 느린 작업이라는 것을 이해합니다.하지만 여전히 ..... 테스트해야한다고 생각합니다.
Øystein Schønning-Johansen

rand()int범위에서를 반환합니다 [0..RAND_MAX]. 그 범위의 하위 범위를 쉽게 할 수있는 uint32_t다음 randomInRange(0, ,b)의 범위에서 값을 생성 없다 (INT_MAX...b].
chux - 분석 재개 모니카

0

[0,1] 범위의 부동 소수점 숫자를 반환합니다.

#define rand01() (((double)random())/((double)(RAND_MAX)))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.