홈 / 사용 가이드

온라인 랜덤 추첨은 정말 공정할까

노트북 화면에서 튀어나오는 주사위와 카드를 돋보기로 살피는 그림

화면에서 돌아가는 룰렛이나 레이스가 정말 공정한지 궁금한 적이 있을 겁니다. 컴퓨터는 정해진 규칙대로만 움직이는 기계인데 어떻게 무작위가 가능한지, 그리고 어디까지 믿어도 되는지 세 가지 질문으로 나누어 설명합니다. 난수가 예측되지 않는가, 범위를 맞출 때 치우치지 않는가, 섞는 절차가 올바른가입니다.

컴퓨터의 난수는 어디서 오나

프로그램이 흔히 쓰는 난수는 사실 계산으로 만든 수열입니다. 시작값이 같으면 같은 수열이 이어지지요. 게임이나 시뮬레이션에서는 이 정도로 충분하지만, 앞의 몇 개를 알면 뒤를 맞힐 수 있다는 약점이 있습니다. 자바스크립트의 Math.random()이 그런 종류이고, 브라우저 문서(MDN)도 이 함수가 암호용으로 쓸 만한 안전한 난수를 주지 않는다고 밝혀 둡니다.

브라우저에는 다른 도구가 있습니다. crypto.getRandomValues()는 운영체제가 기기의 여러 잡음(시간의 미세한 흔들림, 하드웨어 사건 등)을 모아 만든 난수를 건네주는 기능으로, 보안 용도에 쓰는 암호학적 난수입니다. 뽑고는 이쪽을 씁니다. 한 번에 0부터 4,294,967,295 사이의 정수 하나(32비트)를 받아 모든 추첨의 재료로 삼습니다. 이것으로 첫 번째 질문, 「결과를 미리 맞힐 수 있는가」는 답이 됩니다. 그러나 공정함에는 질문이 두 개 더 남아 있습니다.

두 번째 질문: 난수를 원하는 범위의 수로 바꾸는 일

좋은 난수를 받았어도 범위를 맞추는 과정에서 치우침이 생길 수 있습니다. 0에서 255까지의 수 하나를 얻은 뒤 10으로 나눈 나머지로 0~9 중 하나를 고르는 방법을 생각해 보세요. 256은 10으로 나누어떨어지지 않아서 25×10+6입니다. 그래서 0부터 5까지는 256개 값 중 26개씩, 6부터 9까지는 25개씩을 가져갑니다. [계산] 확률로 옮기면 0~5는 각각 26/256 = 10.16%, 6~9는 25/256 = 9.77%입니다.

이 계산이 실제로 맞는지 우리는 500만 번 돌려 확인했습니다. 나머지 방식에서 0~5는 약 10.15%, 6~9는 약 9.77%가 나와 계산값과 0.01%p 안팎으로 가까웠습니다. [실측] 뽑고의 방식은 범위를 넘는 값이 나오면 버리고 다시 받습니다. 같은 실험에서 열 숫자가 모두 9.97%~10.02% 사이에 들어왔어요.

뽑고는 32비트 값을 쓰기 때문에 버리는 값이 훨씬 적습니다. 2의 32제곱은 4,294,967,296인데 10으로 나눈 나머지가 6이라서, 10개 중 하나를 고를 때 버려지는 값은 42억 개 중 단 6개뿐입니다. [계산] 참가자가 1,000명이면 버려지는 값은 296개입니다. 이렇게 거의 버리지 않으면서도 모든 칸이 정확히 같은 몫을 갖게 되는 것이 이 방식의 요점입니다.

0~9 하나 고르기 (500만 번, 이상적인 값 10%)
방식0~5 각각6~9 각각
256개 값을 10으로 나눈 나머지 [계산]10.16%9.77%
같은 방식 [실측]10.15%9.77%
뽑고 방식 [실측]9.97%~10.02%9.99%~10.00%

세 번째 질문: 순서를 섞는 법

난수와 범위가 모두 좋아도 섞는 절차가 틀리면 결과가 치우칩니다. 올바른 절차인 피셔–예이츠는 마지막 칸부터 시작해, 그 칸과 그보다 앞의 칸(자기 자신 포함) 중 무작위로 하나를 골라 서로 바꾸는 일을 두 번째 칸까지 반복합니다. 항목이 A, B, C 셋이라면 맨 뒤 칸은 세 칸 중 하나와, 가운데 칸은 앞의 두 칸 중 하나와 바꿉니다. 선택의 경우의 수가 3×2 = 6가지이고, 서로 다른 선택은 반드시 서로 다른 순서로 끝납니다. 가능한 순서도 3! = 6가지라서 모든 순서가 정확히 한 번씩, 즉 6분의 1씩 나옵니다. [계산]

이 대응이 바로 「정확히 같은 확률」의 근거입니다. 반대로 각 칸을 전체 칸 중 아무 칸과 바꾸는 방법을 보세요. 세 칸이면 3×3×3 = 27가지 경우를 6가지 순서에 나누어야 하는데 27은 6으로 나누어떨어지지 않으므로, 어떤 순서는 반드시 더 자주 나옵니다. [계산] 정렬 함수에 무작위 비교를 넣는 흔한 방법도 같은 종류의 문제가 있습니다. 네 항목을 100만 번 섞은 실험에서 가장 흔한 순서는 18.76%, 가장 드문 순서는 1.54%였습니다(이상적인 값은 4.17%). [실측] 자세한 과정은 「100만 번 섞어 봤습니다」에 있습니다.

이런 도구가 증명할 수 없는 것

공정함을 따질 때는 화면의 연출이 결과에 끼어드는지도 살펴야 합니다. 룰렛이 도는 힘이나 레이스 중의 충돌로 결과가 정해지는 방식이라면 기기의 속도나 화면 크기에 따라 확률이 달라질 수 있습니다. 뽑고는 결과를 시작하는 순간 먼저 정하고 화면은 그 결과에 도착하도록 그립니다. 그래서 이름, 입력 순서, 테마, 기기의 속도가 확률에 가중치를 주지 않습니다. 연출이 아무리 아슬아슬해 보여도 확률에는 손을 대지 않는다는 말은 이 구조를 가리킵니다.

여기까지는 계산의 이야기이고, 실제 상황에서는 다른 한계가 남습니다. 브라우저에서 돌아가는 프로그램은 사용자의 기기 위에서 실행되므로, 누군가 그 기기를 조작했다면 결과를 바꿀 수 있어요. 도구가 「지금 당신이 본 화면이 조작되지 않았음」을 증명할 방법은 없습니다.

다만 어디서 계산되는지에 따라 믿어야 할 대상이 달라집니다. 뽑고의 일반 추첨은 여러분의 브라우저 안에서 계산되므로 서버가 결과를 정해 내려보내는 구조가 아닙니다. 그 대신 믿어야 할 대상이 여러분의 기기와 브라우저로 옮겨 갑니다. 서버가 결과를 정해 알려 주는 도구라면 반대로 그 서버를 믿어야 하지요. 어느 쪽이든 「누가 결과를 만드는가」를 아는 것이 공정함을 따지는 출발점입니다.

그래서 이런 도구는 친구나 동료 사이의 가벼운 추첨에 알맞습니다. 상금이 걸린 대회나 법적인 효력이 필요한 추첨에는 공증이나 제3자의 참관 같은 별도의 절차가 필요합니다. 도구를 쓰더라도 화면을 녹화하거나 여러 사람이 함께 지켜보게 하면 신뢰가 더 올라갑니다.

직접 확인해 보려면 몇 번을 돌려야 할까

도구의 공정함이 궁금해 직접 돌려 보는 분도 있을 텐데, 한 가지 알아 둘 것이 있습니다. 열 칸 중 한 칸이 나올 비율을 세어 볼 때, 시행 횟수가 적으면 우연한 흔들림이 크다는 점입니다. 이 흔들림의 크기(표준오차)는 √(0.1×0.9/횟수)로 계산합니다. [계산] 100번 돌렸을 때는 3.0%p나 흔들리므로 한 칸이 7%나 13%로 나와도 이상하지 않습니다.

위의 나머지 방식처럼 0.15%p쯤 치우친 도구를 가려내려면 흔들림이 그보다 훨씬 작아야 합니다. 100만 번을 돌려야 비로소 0.03%p 수준이 되고, 그제야 0.15%p의 치우침이 우연이 아님을 말할 수 있습니다. 몇십 번 돌려 보는 확인은 아주 큰 치우침만 잡아낼 수 있다는 뜻입니다. 우리가 수백만 번씩 돌린 이유가 여기에 있습니다. 그렇게 돌린 결과는 「뽑고 추첨 검증 보고서」에 모아 두었습니다.

열 칸 중 한 칸의 비율을 셀 때 우연히 흔들리는 크기
시행 횟수표준오차 (이상적인 값 10% 기준)
1003.000%p
1,0000.949%p
10,0000.300%p
100,0000.095%p
1,000,0000.030%p
5,000,0000.013%p

믿을 만한 도구인지 살피는 기준

어떤 추첨 도구를 쓰든 살펴볼 만한 점은 비슷합니다. 난수를 어디서 가져오는지, 범위를 맞출 때 치우침을 없애는지, 섞는 절차가 무엇인지, 같은 이름을 어떻게 세는지, 입력한 순서가 결과에 영향을 주는지, 그리고 이 모두를 확인한 방법과 한계를 밝히고 있는지입니다.

뽑고는 앞의 세 가지를 이 글에서 설명했고, 같은 이름은 별도 참가 항목으로 세며 입력 순서나 이름에 가중치를 주지 않습니다. 확인한 방법은 검증 보고서에 공개했고, 한계는 이 글의 네 번째 절에 적은 그대로입니다. 설명만 있는 도구와 설명에 더해 확인 결과를 내놓는 도구는 다릅니다. 숫자가 틀렸다면 문의 페이지로 알려 주세요. 같은 조건으로 다시 재 보겠습니다.

참고한 자료

바로 써 보기

이런 글도 있어요