핵심 요약
- 난수를 구한 뒤 나머지 연산자(%)로 범위를 제한해 무작위 항목을 뽑는 방식은 특정 항목의 선택 확률이 높아지는 편향이 생깁니다.
- 예를 들어 0~9 난수를 3으로 나누면 40%, 30%, 30%로 갈려 완벽한 균등 분포가 깨지게 됩니다.
- 부동소수점 대신 정수 가중치를 활용해 확률 분포를 명시적으로 넘겨주는 고수준 API를 사용하는 것이 안전한 해결책입니다.
요약 프로그래밍할 때 여러 선택지 중 하나를 무작위로 뽑기 위해 큰 난수를 구한 뒤 나머지 연산자(Modulo, %)를 사용하는 방식은 개발자들 사이에서 매우 흔히 쓰이는 패턴입니다. C언어의 `rand()`나 일반적인 `random_u64()` 함수를 호출해 `choices[r % 10]` 형태로 작성하는 식인데, 직관적이고 간단해 보이지만 사실 여기에는 심각한 확률 왜곡 문제가 숨어 있습니다.
가장 단순한 예로 0부터 9까지 10개의 정수 중 하나를 균등하게 뽑은 뒤, 이를 3개의 아이템 중 하나를 고르기 위해 `% 3` 연산을 적용하는 상황을 들 수 있습니다. 직관적으로는 각 아이템이 동일하게 33.3% 확률로 선택될 것 같지만, 실제 결과를 매핑해 보면 {0, 3, 6, 9}는 1번 아이템(40%), {1, 4, 7}은 2번 아이템(30%), {2, 5, 8}은 3번 아이템(30%)에 배정됩니다. 즉, 입력 범위가 나누어떨어지지 않으면 특정 선택지의 당첨 확률이 더 높아지는 모듈로 편향(Modulo Bias)이 발생합니다.
글쓴이는 이러한 실수가 잦은 근본적인 원인으로 저수준 난수 API 설계를 지적합니다. 단순히 균등 난수를 반환하는 함수 대신, 선택지 목록과 각 확률(또는 가중치)을 명시적으로 전달받는 `random_choice()` 형태의 고수준 API를 사용하는 것이 안전하다는 설명입니다. 특히 합이 1.0이 되어야 하는 부동소수점 방식보다는, 파이썬 표준 라이브러리처럼 정수형 상대 가중치(Relative Integer Weights, 예: 파란색 10개, 빨간색 5개)를 넘겨 전체 합 대비 비율로 자동 계산하게 만드는 방식이 부동소수점 오류도 피하고 개발자의 실수를 원천 차단하는 가장 직관적인 설계라고 강조합니다.
Sponsored · 광고