요새 Nature of Code 라는 책을 간간히 보고 있는 중인데,
Javascript의 Math.random 이라는 함수가 단순히 난수를 생성하는 지 또는 정규분포를 나타내는지 궁금하여 알아보게 되었다.
수학적 지식이 뛰어나지는 못해 작성한 것이 정확하진 않을 수 있습니다. 참고만 해주세요... 오류가 있다면 지적 부탁드립니다.
ECMA 공식 문서를 참고해보면, Math.random에 대해 다음과 같이 적혀있다.
US: Returns a Number value with positive sign, greater than or equal to +0𝔽 but strictly less than 1𝔽, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-defined algorithm or strategy. This function takes no arguments.
KO: 구현-정의 알고리즘 또는 전략을 사용하여, 0 ≤ x < 1 범위에서 거의 균등한 분포로 랜덤 혹은 유사하게 양의 기호의 수를 반환한다.
이 함수는 arguments 를 가지지 않는다.
즉, 이 말에 따르면 다음 그림과 같이 Math.random 함수가 정규분포가 아닌 거의 균등한 확률로 난수를 만들어 내는 함수임을 알 수 있다.
그럼, 어떻게 해야 정규분포를 따르게 하는 함수를 만들 수 있을까.
이 부분에 관련해서는 여러 글들을 살펴보았고 간편하게 쓸 수 있을 법한 답변을 위주로 살펴보았다.
1. 만들어 놓은 라이브러리를 사용한다.
https://github.com/errcw/gaussian
이미 엄청난 사람들이 만들어 두었다. 그냥 다운받아 쓰기만 하면 된다.
하지만.. 나같이 그냥 라이브러리 같은 것을 사용하고 싶지 않은 사람들을 위해..
2. Math.random을 더해 평균값으로 정규화를 해본다.
function randomG(v) {
var r = 0;
for (var i = v; i > 0; i--) {
r += Math.random();
}
return r / v;
}
가장 간단한 식으로 표현할 수 있다. 하지만 내가 원하는 정도의 분포는 나오지 않았다.
테스트 케이스가 큰 상황에서 사용하면 괜찮을 것 같기도 하다.
3. 척도(Scaled) 정규 분포의 사용
function gaussianRand() {
let rand = 0;
for (let i = 0; i < 6; i += 1) {
rand += Math.random();
}
return rand / 6;
}
function gaussianRandom(start, end) {
return Math.floor(start + gaussianRand() * (end - start + 1));
}
//출처: https://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve/39187274#39187274
표준 편차가 1이 나오지 못한다. 그래서 완전한 정규 분포라고 보긴 어렵다고 한다.
극점에 있는 값들이 잘 안나오는 건 아쉽지만 괜찮은 코드인 것 같다.
4. Box-Muller 변환을 이용한 정규분포
function randn_bm(min, max, skew) {
let u = 0, v = 0;
while (u === 0) u = Math.random() //Converting [0,1) to (0,1)
while (v === 0) v = Math.random()
let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v)
num = num / 10.0 + 0.5 // Translate to 0 -> 1
if (num > 1 || num < 0)
num = randn_bm(min, max, skew) // resample between 0 and 1 if out of range
else {
num = Math.pow(num, skew) // Skew
num *= max - min // Stretch to fill range
num += min // offset to min
}
return num
}
//출처: https://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve/39187274#39187274
이것도 마찬가지로 극 값이 잘 안나오긴 하지만, 평균값을 기준으로 균등하게 잘 나오는 것 같다.
하지만 수식을 이정도로 써야한다면 그냥 라이브러리 쓸 것 같기도 하다.
참고하면 좋은 사이트
'Programming > Javascript' 카테고리의 다른 글
만약 영상에 배속기능이 없다면? (ex. 학교 강좌) (4) | 2022.08.12 |
---|---|
OverRiding(오버라이딩)과 OverLoading(오버로딩) 간단 정리 (0) | 2021.06.05 |
간단하게 훑어보는 함수형 프로그래밍 #1 (0) | 2020.05.04 |
ES6 Class (0) | 2020.04.23 |
한 줄짜리 if 문, for 문 그리고 함수 (0) | 2020.04.22 |