커피 한 잔 사주기
블로그 목록으로
Education

진짜 무작위 vs 의사 무작위: 실제로 중요한 것

Random Select Team•2026-04-01•7 min

버튼을 누르면 숫자가 나오고, 그게 무작위라고 여겨져요. 물어볼 만한 질문은 무엇이 그걸 만들었느냐예요. 두 답 중 하나는 검증 가능하고 다른 하나는 그렇지 않으니까요.

진짜 무작위성은 어디서 오는가

진짜 무작위성은 이전 상태로 결정되지 않는 물리적 과정에서 나와요:

  • 방사성 붕괴 — 원자가 붕괴하는 정확한 순간은 예측할 수 없어요
  • 열잡음 — 저항기에서 생기는 무작위 전압 변동
  • 대기 잡음 — 번개 활동에서 나오는 배경 잡음
  • 양자 측정 — 진정으로 결정되지 않는 결과

이것들은 무작위성의 근사가 아니에요. 과거에 대한 어떤 지식으로도 결과가 결정되지 않는다는 의미에서 무작위예요.

컴퓨터는 대신 무엇을 하는가

컴퓨터는 이것들을 직접 관찰할 수 없어서, 하드웨어 생성기가 이것들을 표본으로 삼아요. 생 바이트는 /dev/urandom이나 그에 준하는 운영체제 원천에서 오고, 그것 자체가 물리적 과정에서 시드를 받아요. 이게 진짜 난수 생성기예요.

훨씬 흔한 경우는 의사 난수 생성기예요. 무작위처럼 보이는 수열을 만드는 결정론적 알고리즘이죠.

next = (previous × multiplier + increment) mod modulus

결정적인 성질은 미묘하지 않아요. 알고리즘과 시드를 알면 그 수열이 앞으로 만들 모든 값을 계산할 수 있어요. 근사가 아니라 정확히요.

그래서 거의 모든 웹사이트가 쓰는 Math.random()은 중요한 일에 적합하지 않아요. 출력이 내부 상태로 결정돼요. 관찰한 출력에서 그 상태를 복원하면 앞으로의 모든 결과를 예측할 수 있어요.

가장 흔히 인용되는 예는 선형 합동 생성기의 전체 상태를 연속된 출력 몇 개로 복원할 수 있다는 거예요. Python의 기본값인 Mersenne Twister는 624개의 출력이 있어야 복원되는데, 624는 몇 초면 도달하는 숫자예요.

Xorshift와 비슷한 빠른 생성기도 다른 형태로 같은 성질을 가져요. 통계적 품질은 뛰어나지만 상태를 알면 완전히 예측 가능해요.

실제로 중요한 중간 지대

대부분의 설명이 건너뛰는 부분이고, 실제로 답을 좌우하는 부분이에요.

도구로 생성한 난수

현대 웹 플랫폼은 호출마다 생 /dev/urandom을 쓰지 않아요. 암호학적으로 안전한 PRNG를 써요. 결정론적 알고리즘이지만 하드웨어 엔트로피로 시드를 받고, 출력을 관찰해도 상태를 복원할 수 없도록 설계됐어요.

이 둘은 자주 뒤섞여서, 구분을 정확히 짚을 가치가 있어요:

하드웨어 TRNG CSPRNG 일반 PRNG
물리적 엔트로피 기반 예 예 아니요
상태가 주어지면 결정론적 아니요 예 예
출력이 상태를 드러냄 아니요 아니요 예
상품 추첨에 적합 예 예 아니요

CSPRNG는 여러분이 쓰는 모든 소프트웨어가 결정론적인 것과 같은 의미에서 결정론적이에요. 이것이 받아들여지는 이유는 이미 내보낸 값으로는 상태를 복원할 수 없기 때문이에요.

브라우저는 이를 crypto.getRandomValues()로 제공해요. RandomSelect가 쓰는 원천이에요.

공정성은 두 번째 문제

좋은 원천이 있어도 균등성을 틀리기 쉬워요. 6면 주사위는 간단해요. 여섯 개 값이 똑같이 나올 확률이죠. 7면 주사위는 그렇지 않고, “이름 40개 중 1개 고르기”도 그렇지 않아요.

순진한 방식, 즉 0에서 1 사이의 무작위 실수를 범위에 맞춰 늘리는 방식은 낮은 쪽에 편향을 만들어요. 이름이 40개면 첫 번째가 마지막보다 조금 더 자주 나와요. 일부 무작위 값이 마지막 구간을 넘어서고, 그것이 고르지 않게 버려지기 때문이에요.

올바른 방식은 기각 샘플링이에요. 뽑은 값이 불완전한 마지막 구간에 들어가면 버리고 다시 뽑아요. 그러면 분포가 정확히 균등해져요.

편향이 작아서 놓치기 쉬워요. 실제 구현은 범위를 벗어난 값을 버리고 다시 뽑으므로, 모든 항목이 정확히 1/N의 확률을 가져요. 이름 40개 추첨에서도 마찬가지예요. 실수를 늘리는 구현은 첫 번째 이름에 아주 약간 더 높은 확률을 줘요.

같은 기법이 짧은 ID 생성기에도 나와요. 코드 주석에는 허용률과 그로 인한 약 천만 분의 이 정도의 편향이 적혀 있어요. 무시해도 될 만큼 작고, 부주의한 구현이라면 눈치채지 못했을 만큼 작아요. 그래서 측정할 가치가 있어요.

실제로 이것이 뜻하는 것

점심 메뉴를 고르는 데는 이런 게 아무 상관 없어요. 어떤 생성기든 괜찮은 점심을 골라 줘요.

상품 추첨, 직원 배정, 평판이 걸린 일이라면 문제는 그 출력을 미리 예상할 수 있었느냐예요. Math.random()이라면 원리상 가능해요. crypto.getRandomValues()라면 불가능해요. 이게 “우리가 무작위라고 말한다”와 “메커니즘이 무작위이게 만든다”의 차이예요.

애니메이션에 관해 자주 혼동되는 관련된 점이 하나 있어요. 돌아가는 룰렛에서 결과는 룰렛이 움직이기 전에 정해져요. 애니메이션은 그 결과를 향해 재생될 뿐이에요. 일부 독자는 이걸 조작의 증거로 받아들여요. 정반대예요. 결과가 이미 정해져 있어 타이밍으로 좌우할 수 없으니, 누구도 이용할 입력이 없어요. 화면 연출은 이미 정해진 값 위의 극적인 표현일 뿐이에요.

직접 시험해 보기

코드가 필요 없는 간단한 연습이에요. 주사위를 20번 굴려 결과를 적으세요. 그리고 연속된 결과가 있는지 보세요.

찾게 될 거예요. 6이 세 번 연속 나오는 일은 대략 50번 굴릴 때마다 한 번 일어나요. 이건 주사위가 조작됐다는 신호가 아니라, 공정한 과정을 짧은 표본으로 들여다볼 때의 모습이에요.

그다음 100번 굴려 각 면을 세어 보세요. 차이가 줄어들어요. 아무것도 수렴하지는 않아요. 메울 부족분이 애초에 없었으니까요. 충분히 자세히 보면 이것이 독립성이 뜻하는 바예요.

더 읽어볼 곳

이 사이트의 공정성 페이지에서 기각 샘플링 단계를 포함한 실제 구현을 설명해요. 문제 제기가 예상되는 결정에 도구를 고른다면 한 번 읽어 볼 만해요.

실용적인 요약은 짧아요. crypto.getRandomValues()를 쓰고 범위를 벗어난 추첨을 버리는 도구는 옳은 일을 하고 있고, 그 말을 그대로 믿을 필요도 없어요. 대신 메커니즘을 따져 보면 돼요.

RST

Random Select Team

Random Select의 숙련된 데이터 분석가이자 게임 이론가입니다. 디지털 공정성, 확률 수학, 랜덤 의사결정 시스템에서 10년 이상의 경험을 보유하고 있습니다.

이 기사 공유