본문 바로가기
STORAGE

랜덤의 비밀: 우연 또는 조작

2023. 12. 27. 18:03

랜덤, 도박사의 오류

어느덧 한 해가 마무리 되어 가고 새해가 밝아오고 있습니다. 한 해를 돌이켜 보았을 때 좋았던 일들이 많으셨나요, 안 좋았던 일들이 많으셨나요?
안 풀리는 일들만 기억에 남아 "왜 나에겐 행운이 따라주지 않을까?"란 생각과 함께 좋았던 기억을 놓치고 계시진 않으셨나요? 현재 불운을 많이 겪고 있다는 생각이 들어 좌절하지 않으셨으면 좋겠습니다.

 

동전 앞뒷면처럼 인생의 결과는 한 번에 결정되지 않고 우리는 살아가면서 매 순간 수없이 많은 행운의 동전을 던지며 살아갑니다.
하나의 동전을 10번 던져 앞면이 10번 나왔다고 할 때, 11번째 동전을 던집니다. "앞면이 10번 나왔으니 다음번 11번째에도 앞면이 나오겠다." 또는 "앞면이 많이 나왔으니 이번에는 뒷면이 나오지 않을까?"라고 생각하실 수도 있습니다. 이는 모두 도박사의 오류에 빠진 생각입니다. 11번째 동전이 앞면이 나올지 뒷면이 나올지는 50:50 확률로 랜덤(random)한 결과입니다. 왜냐하면 11번째의 결과는 이전 시행과 독립 시행이기 때문입니다.

 

이번 주제는 랜덤에 대해 알아보고, 컴퓨터 과학에서의 확률의 비밀에 관해 얘기해보려 합니다.

 

도박사의 오류

랜덤, 도박사의 오류
룰렛 게임 (출처: https://en.wikipedia.org/wiki/Roulette)

1913년 몬테카를로의 카지노에서 룰렛 게임이 진행되었습니다. 이때 룰렛에 구슬이 20번 연속해서 검은색 위로 떨어졌고, 지켜보고 있던 많은 사람은 구슬이 빨간색 위로 떨어질 때가 되었다 생각하여 빨간색에 배팅하였습니다. 하지만 계속하여 검은색으로 떨어져 많은 사람이 파산하였고, 27번째가 (되어서야) 빨간색에 떨어졌습니다. 이 사건으로 인해 "몬테카를로 오류(Monte Carlo Fallacy)"이자 "도박사의 오류(Gambler`s Fallacy)"라는 명칭이 붙었습니다.

 

야구 경기에서 타율이 3할인 한 선수가 4번째 타석에 등판하였습니다. 이 타자는 이전 세 타석에서 모두 무안타였습니다. 이때 해설자가 얘기합니다. "이 타자, 지금까지 안타가 없었으니까 이제 한 방 나올 때가 됐습니다." 이 또한 도박사의 오류에서 나오는 생각입니다. 3할대 타자는 여러 타석에서 안타를 친 결과의 평균인 통계적 확률의 타자이지, 3타석마다 안타를 때리는 수학적 확률의 타자가 아니라는 의미입니다.

 

도박사의 오류는 누구나 알면서도 정작 실제 상황에서 오류에 빠지게 됩니다. 동전 던지기, 룰렛의 색깔은 매번 시도할 때마다 확률이 달라지는 게 아닙니다. 확률은 변함이 없으며, 시행마다의 연관성도 없습니다. 심지어 동전과 구슬은 직전의 결과를 기억하지도 않습니다. 그런데도 사람들은 이전 시행의 결과를 근거로 다음 시행의 결과를 거의 믿습니다.

 

큰 수의 법칙과 보상심리

랜덤, 도박사의 오류
용인 모 복권판매점 (출처: https://www.chosun.com/national/national_general/2021/02/25/AZJPZZGD2VF2HKHI5MR5MRT3VI)

- "역대 로또 당첨 번호 중 n번이 적게 나왔으니 이번엔 n번을 선택하자."
- "이 로또 판매점이 명당이야. 여기서 로또를 사면 당첨 확률이 높을 거야."
- "딸을 다섯 낳았으니 다음 여섯째 아이는 아들일 거야."

 

사람들은 왜 이러한 오류를 범할까요?

사람들은 동전을 던질 때, 계속해서 연달아 앞면이 나올 확률보다 앞면-뒷면-앞면-뒷면-앞면-뒷면이 나올 확률이 훨씬 높다고 생각합니다. 여러 차례 던진다면 앞면과 뒷면이 나오는 횟수가 공평할 것으로 생각하는 거죠. 그러나 10번을 던질 때는 반드시 앞면 5번, 뒷면 5번이 아니라 앞면만 10번 나올 수도 있습니다. 물론 앞면이 나올 확률은 2분의 1이기에, 여러 번 동전을 던지게 되면(여기서 여러 번은 생각보다 아주 많은 횟수입니다.) 앞면이 나온 횟수와 뒷면이 나온 횟수는 공평한 결과에 수렴하게 됩니다. 이를 "큰 수의 법칙"이라고 합니다. 명당인 로또 판매점일수록 로또를 사는 사람이 많아지기에 당첨자가 나온 횟수가 많다는 거죠.

우연은 기억도 양심도 없다. 부부가 여섯 번째 딸을 가질 확률은 여전히 1/2이다. 룰렛에서 붉은색이 나올 확률도 여전히 1/2이며, 주사위에서 2가 나올 확률은 언제나 1/6이다. 바꿔말하자면, 동전을 던져서 앞뒤를 알아맞히는 게임에서 앞면이 계속해서 다섯 번이 나왔다고 할 때 여섯 번째 시도에서도 앞면이 나올 확률은 그전과 다름없이 역시 1/2이다. 동전은 앞에 던진 결과를 기억하지 않는 것이다.
- 마틴 가드너 , `이야기 파라독스` 제5장 확률의 파라독스 - `도박사의 궤변`.

 

또한 이 오류는 "모든 독립사건은 앞에서 일어난 사건과 독립적으로 일어난다."라는 확률 이론의 가정을 받아들이지 않는 데서 발생합니다. "이만큼 잃었으니 다음번엔 운이 좋겠지."라는 일종의 보상 심리라고도 할 수 있습니다.

따라서 도박사의 오류는 "각 시행마다의 확률이 이전의 결과와 무관함에도 많은 시행이 있으면 언젠가는 나온다. 그것은 바로 지금!"이라는 생각에서부터 시작합니다. 충분히 큰 수를 시행하지 않았음에도 이전 몇 번의 시행을 근거로 다음 결과를 믿는 것입니다.


손기술 없는 컴퓨터

랜덤, 도박사의 오류
리그오브레전드 치명타 공격 (데미지 77 - 일반 공격 / 데미지 135 - 치명타 공격)

요즘 유행하는 리그오브레전드(이하 LOL)라는 PC게임에서는 치명타(크리티컬 히트)라는 개념이 있습니다. 치명타란 확률에 따라 평소의 공격보다 더 강한 공격을 하는 것을 말합니다. 여기서 치명타확률은 0~100%의 수치로 이루어져 있으며 기본 공격마다 특정 % 확률로 치명타 공격이 이루어집니다.

예를 들어 치명타 확률이 50%인 캐릭터가 있습니다. 이 캐릭터는 50% 확률로 치명타 공격을 합니다. 일반 공격을 2번 하면 그중에 한번은 치명타 공격을 할 것이라고 "기대"할 수 있는 거죠. 하지만 앞서 말한 동전 던지기 때와 같이 실제로 같은 결과가 연속해서 나올 수 있습니다. 동전의 "앞면-앞면"과 같이 "치명타 공격-치명타 공격"이라는 결과를요.

치명타 확률이 50%로 똑같은 두 캐릭터 A와 B가 승부를 겨룹니다. A는 정말로 운이 좋게도 "치명타 공격-치명타 공격"을 했습니다. B는 운이 좋지 않아 "일반 공격-일반 공격"이라는 결과가 나왔습니다. 일반 공격보다 강한 치명타 공격을 맞은 캐릭터 B는 억울합니다. 물론 앞서 말한 큰 수의 법칙에 의하여 이후 많은 일반 공격을 하면 결과는 수학적 확률에 따라 캐릭터 B도 치명타 공격을 할 수 있습니다. 아직 B의 동전의 앞면은 나오지 않았을 뿐이니까요. 하지만 B는 기분이 나쁠 것입니다. 이미 게임의 승패는 결정이 난 이후에 일어날 일이기 때문입니다.

 

이처럼 운의 요소로 결과가 정해지는 상황을 줄이고자 개발자들은 확률 보정 메커니즘(mechanism)을 게임 시스템 내에 숨겨놓습니다. 50%의 확률로 치명타 공격을 하는 캐릭터 B가 있습니다. 처음 공격에는 표기된 50%보다 낮은 30%의 확률을 가지고 공격합니다. 30%의 확률로 시작하여 치명타 공격이 발동하지 않으면, 다음 공격에는 임의의 상수값(=c값)만큼 확률을 점점 높여줍니다. 첫 번째는 30%, 두 번째는 40%, 세 번째는 50%와 같은 예시처럼요. B는 정말 운이 좋지 않아 3번의 공격을 시행했음에도 치명타 공격이 발동하지 않았다고 가정했을 때, 4번째 공격에서 치명타 공격이 나올 확률을 원래 표기된 50%보다 높게 60% 또는 70%와 같이 시스템적으로 보정해주는 메커니즘입니다. 5번째 공격에서 치명타 공격이 발동할 경우, 발동한 시점에 다시 치명타 확률은 초기 설정값 30%로 초기화됩니다. 초기에는 표기된 50% 확률보다 낮은 확률로 시작하여 과도한 행운을 주지 않고, 점점 확률을 높여주어 불운한 사람도 나중에는 확정적으로 결과를 얻을 수 있도록 해주죠.

 

이를 의사 난수 분포, Pseudo Random Distribution(PRD)이라고 합니다. 이러한 시스템적인 보정을 통해 도박사의 오류가 어느 정도는 오류가 아니게 해줍니다. 이 의사 난수 분포, PRD는 앞서 말했듯 개발자들이 "숨겨"놓았다고 했습니다. 정확한 초기 설정값과 증가하는 보정치-임의의 상수값(=c값)을 알게 되면 의도적으로 다음 시행의 결과를 조절할 수 있기 때문이죠. 플레이어 입장에선 일부러 공격을 상대방한테 하지 않고, 무의미한 다른 타겟에 시행하며 확률을 보정 받아 높인 후 충분한 시행이 쌓였다는 생각이 들 때, 높아진 확률의 공격을 상대에게 시행하여 치명타 공격이 나올 것이라고 기대하는 것입니다.

 

컴퓨터는 논리밖에 모르는 아주 논리적인 기계이기 때문에 확률을 판정하는 방법과 랜덤(Random) 즉, 무작위의 개념을 이해시켜줘야 하는 것입니다.

 

 

랜덤인척 하는 랜덤

설명을 위해 예시로 간단한 코드를 작성해보았습니다.

import random #파이썬 랜덤 모듈

def roll_dice(): #주사위 굴리기 함수
return random.randint(1, 6) #1부터 6까지 랜덤한 정수를 리턴

# 주사위를 굴려서 결과를 출력
result = roll_dice()
print(f"주사위 결과: {result}")

 

먼저 랜덤(Random)이란 어떠한 사건이 규칙성 없이 무작위로 발생하는 것을 의미합니다. 위의 코드를 실행했을 때, 출력된 1부터 6까지 랜덤한 출력 결과는 정말 주사위의 눈처럼 1/6(16.66%) 확률일까요? 그렇다면 프로그래밍에서 rand( ), random.random( ), Math.random( ) 등 난수를 생성하기 위한 여러 함수는 어떠한 근거로 우리에게 랜덤한 값을 출력해주는 것일까요?

먼저 의사 난수(Pseudo Random Number)의 개념을 알아야 합니다.

 

의사 난수, 擬似(본뜰 의, 비슷할 사)亂數, Pseudo Random Number, PRN

즉, "랜덤인척 하는 랜덤"이라는 뜻입니다. 컴퓨터는 정해진 입력에 따라 정해진 출력을 할 뿐, 컴퓨터가 무의식적으로 또는 우연히 하나를 고를 수 없습니다. 따라서 어떠한 규칙을 정해주고 여러 계산 과정을 거쳐 사람이 보기에 어느 정도 우연성을 가지고 있다면 이를 랜덤하다라고 보는 것이 의사 난수(Pseudo-Random Number)입니다.

 

이 무작위처럼 보이는 랜덤은 어떠한 규칙을 정해주어야 하는데, 가장 간단한 방법으로는 난수표를 미리 정해두고 출력을 하는 것입니다. 오래전 MS-DOS 시절 테트리스는 이러한 방식으로 블록의 순서가 모두 똑같았습니다. 이를 해결하는 방법으로 여러 난수표를 정해두고 어떠한 상황마다 매번 다른 난수표를 읽도록 하였는데, 이 어떠한 상황을 "시드(Seed)"라고 합니다. 하지만 이 시드값이 똑같으면 결국 출력되는 난수 또한 똑같아지는 문제가 발생하죠.

 

즉, 랜덤한 사건을 만들기 위해 또 다른 랜덤한 무언가를 컴퓨터가 입력받아야 한다는 의미인데, 가장 간단하게 사용할 수 있는 시드값으로는 현재 시각의 밀리초(ms)입니다. 예를 들어 컴퓨터에서 사용하는 밀리초(ms) 단위의 소수점 n번째 자리의 숫자를 시드값으로 사용한다던가, Windows에선 시간 이외에도 컴퓨터가 켜져 있는 시간 (ns단위), CPU 메모리의 클럭/온도 등 다양한 방식으로 시드값을 사용합니다.

 

이렇게 시드(Seed)값을 정하였으면, 특정한 공식을 통해 다시 랜덤한 난수를 발생시켜야 합니다. 프로그래밍 함수 모듈들은 여러 방식의 난수 생성 알고리즘을 사용하고 있는데, 대표적으로 세 가지가 있습니다.

 

1. 중앙제곱법(Mid Square Method)

1949년 폰 노이만이 고안한 의사 난수 생성 방식입니다. 초기의 값(Seed)을 거듭제곱하고 가운데 a 자리의 수만큼 추출하는 방법입니다. 생성한 난수의 품질이 좋지 않아 현재에는 잘 사용하지 않습니다.

 

 

2. 선형합동법((Linear Congruential Method)

C의 rand( ) 함수에서 사용하는 알고리즘이며 계산이 빠르고 간단하기에 예전부터 널리 사용되었습니다. 하지만 문제는 ANSI C 표준으로 변수들이 정해져 있어, 이전 결과를 기반으로 다음 rand 함수의 결과를 예측할 수 있죠.

 

3. 메르센 트위스터(Mersenne Twister)

엑셀, MATLAB, PHP, Python, R, C++ 등에서 사용하고 있는 난수 생성 알고리즘이며, 메르센 트위스터라는 이름은 이 알고리즘의 난수 반복 주기가 메르센 소수인 데서 유래했습니다. 메르센 소수를 이용하며 선형 합동법보다 우수한 난수의 품질과 속도를 인정받아 현재 많이 사용되고 있습니다.

이처럼 난수 생성 알고리즘을 통하여 랜덤처럼 보이는 난수를 생성하지만, 근본적으로 시드값을 기반으로 특정한 공식을 거친 의사 난수는 완전한 무작위라고 볼 수 있습니다. 극단적으로 시드값을 선정하는 방식이 단순할 경우, 컴퓨터 전원을 켰을 때 시각이 같거나 버튼을 클릭한 시점이 같을 때, 같은 결과가 출력되는 상황이 발생할 수도 있다는 말입니다. 같은 의미로 시드 기반 난수로 암호화키를 생성하면 나머지 키값을 유추하여 보안상의 문제가 발생할 수도 있습니다. 어떠한 시스템에서 사용하는 난수 생성 알고리즘을 알고 있다면 특정한 시간대에 특정한 액션으로 원하는 결과를 얻도록 악용할 수 있다는 거죠. 반대로 시드값을 정해놓고 도박의 결과를 미리 세팅할 수도 있습니다. 따라서 이러한 난수 생성 방식과 확률을 시스템 개발자들은 숨겨 놓을 수밖에 없다는 말입니다. 

 

공개되지 않는 "랜덤인척 하는 랜덤"은 실제 많은 응용 프로그램에 사용됩니다. 대다수의 확률적인 요소를 포함한 컴퓨터 프로그램에서는 유사 난수 방식을 통해 확률을 통제합니다.

 

 

마치며

최근 게임업계 내에서는 확률형 콘텐츠에 대한 많은 이슈가 있었습니다. 확률을 공개하지 않았거나, 공개되었더라도 표기된 확률에 따라 실제 결과가 나오지 않아 확률을 조작한 것이 아니냐는 의혹에서부터 시작하였습니다. 성공 확률 30%를 보고 "할 만한데?"라고 생각하거나, 실패 확률 1%일 때 "성공 확률 30%는 안 되던데, 실패 확률 1%는 왜 걸리는 걸까"라는 도박사의 오류에 빠지지 않으셨으면 합니다. 사람들은 어떤 사건의 확률을 평가할 때 기억에 남는 사건일수록 더 높게 평가하는 경향이 있습니다. 이를 가용성 편향이라고 하는데, 이를 통해 여러 사람의 확률 표본을 잊고 본인의 불운만을 기억하고 컴퓨터의 확률에 의문을 가지는 것이죠. 하지만 컴퓨터의 확률은 숨겨져 있을 뿐, 꽤 논리적인 방식으로 통제되고 있으니 어느 정도는 의심을 거두셔도 될 것 같습니다. 

 

우리는 컴퓨터와 함께인 시대에 살고 있습니다. 무한한 데이터의 세상 속에서 확률에 대해 올바른 이해를 하고 숫자 속에 숨겨진 진실을 파악하셨으면 좋겠습니다. 서두에서 말씀드렸듯이 지금 당장 불운한 순간만 보고 좌절하셨다면, "나중에는 좋은 일이 더 많이 일어나겠구나."라는 생각을 가지시는 것은 어떨까요? 앞으로 여러분의 행운의 동전 던지기는 계속될 것이고, 독립시행의 결과는 결국 공평하기 때문입니다.

 

 

참고자료


 

EDITOR

이준석

Bioinformatic System Dept. · Junior Consultant

댓글