참고용

Javascript) Math.random()을 통해 1~100까지 랜덤한 정수를 구하는 방식에 대하여 올림과 내림에 관한 고찰

tierr 2025. 5. 9. 09:45

다음 Javascript 코드는 1부터 100까지 랜덤한 정수를 구하는 계산이다.

// 1. Math.random() * 100은 0 이상 100 미만의 소수를 생성합니다.
// 2. Math.floor(Math.random() * 100)은 이 값을 내림 처리하여 0부터 99까지의 정수를 생성합니다.
// 3. 마지막으로 + 1을 더해 1부터 100까지의 정수를 생성합니다.

let randomInt = Math.floor(Math.random() * 100) + 1;

(0~100 의 난수를 내림처리 후 +1) 이런 방식으로 처리를 하는걸까? 
(0~100의 난수를 올림처리) 를 하면 코드가 더 간결하지 않을까?
= Math.floor(Math.random() * 100) + 1; 대신에 Math.ceil(Math.random() * 100) 를 사용해도 되지 않을까?

 

..라는 궁금증이 생겼고, 이에 대해 이해한 내용을 기록하고자 본 게시글을 작성했습니다.


결론부터 말하자면, Math.floor(Math.random() * 100) + 1을 사용해야 한다.
Math.ceil(Math.random() * 100)  를 사용하면 1이 상대적으로 적게 나오기 때문에 불공평하다! 


✅ 1. 질문의 시작

Math.ceil(Math.random() * 100)을 실행하면 1부터 100까지 랜덤한 정수가 나와야 합니다.
하지만 실제로는 1이 상대적으로 적게 나오는 현상이 발견됩니다.


✅ 2. 헷갈리는 이유는 이론적인 기대값 때문

  • 0.000 ~ 0.999 → 1
  • 1.000 ~ 1.999 → 2
  • ...
  • 99.000 ~ 99.999 → 100

모든 구간 길이는 1.0으로 이론적으로 균등하므로
각 숫자가 같은 확률로 나와야 할 것처럼 보입니다.


❗ 3. 그런데 실제로는 왜 1이 덜 나올까?

📌 원인 1: 부동소수점 정밀도 문제

  • 실수는 무한히 많지만, 컴퓨터는 64비트(고정된 크기)로 표현합니다.
  • 특히 0~1 구간은 이진수로 정밀하게 표현하기 어려움.
  • → 표현 가능한 숫자가 상대적으로 적고 희박합니다.

📌 원인 2: 그 결과, 표현 가능한 값의 밀도 차이

  • 0.00001 ~ 0.99999 사이에는 표현 가능한 값이 드뭅니다.
  • 1.00001 ~ 1.99999 구간은 상대적으로 더 조밀하게 표현 가능.
  • → 따라서 0~1에서 1이 나올 확률이 상대적으로 줄어듭니다.

✅ 4. 시뮬레이션을 통해 확인하기

1천만 개의 Math.random() * 100 실수 샘플을 생성해보면,
각 구간의 길이는 같지만 실제로 표현된 숫자의 밀도 차이로 인해 1의 빈도가 낮게 나옵니다.

ChatGPT 를 통한 난수 시뮬레이션


✅ 5. 올바른 해결책

Math.floor(Math.random() * 100) + 1;
  • 0~99를 만들고, +1 해서 1~100을 생성
  • 정수 구간에 대해 균등한 확률 분포가 보장됩니다.

🎯 최종 요약

  • 문제 원인: 부동소수점 정밀도 + 표현 가능한 실수 수의 밀도 차이로 인해 0~1 구간은 표현 가능한 실수가 희박함
  • 결과: 1이 나올 확률이 상대적으로 줄어듦
  • 추천 : 그러니 1부터 100까지의 정수를 생성하고 싶다면 Math.floor(...)+1 방식을 사용해야 한다
💡 덤: 부동소수점이란?
실수는 무한히 많지만, 컴퓨터는 메모리가 한정되어 있어서 유한한 비트 수로만 실수를 표현합니다.이를 위해 사용하는 방식이 부동소수점(Floating-point) 표현입니다.
예: 0.1 → 2진수로는 0.0001100110011...