Box-Muller Transform
Quick-and-dirty visualization of the Polar Form of the Box-Muller transform.
by Steven Sell
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div id="holder">
</div>
<br />
Gaussian Distribution of 1000 random values using the Polar Form of the Box-Muller Transform.
<br /><br />
A performance comparison between the Basic and Polar forms may be found <a href="https://jsperf.com/box-mullerperformance">here</a>.
<br /><br />
X-Axis: Value <br/>
Y-Axis: Number of value occurences <br/>
<br/>
Min: <span id="minval"></span><br />
Max: <span id="maxval"></span><br />
CSS
#holder {
width: 500px;
height: 100px;
border: 1px solid black;
background-color: #FFFFFF;
}
.value {
position: absolute;
width: 2px;
height: 2px;
background-color: rgb(100, 155, 100);
}
#zero {
position: absolute;
height: 100px;
width: 1px;
background-color: rgb(255, 0, 0);
font-size: 10px;
color: rgb(255, 0, 0);
}
#zerotext {
position: absolute;
bottom: 0;
margin-left: 3px;
}
JavaScript
/**
* Polar Form of the Box-Muller Transform for normally distributed PRNG generation.
* See the following for a perfomance comparison between Basic and Polar forms:
*
* http://jsperf.com/box-mullerperformance
*/
function gaussianRand() {
this.generate = true;
this.value0 = 0.0;
this.value1 = 0.0;
if(this.generate) {
var x1 = 0.0;
var x2 = 0.0;
var w = 0.0;
do {
// Math.random() gives value on range [0, 1) but
// the Polar Form expects [-1, 1].
x1 = (2.0 * Math.random()) - 1.0;
x2 = (2.0 * Math.random()) - 1.0;
w = (x1 * x1) + (x2 * x2);
} while(w >= 1.0);
w = Math.sqrt((-2.0 * Math.log(w)) / w);
this.value0 = x1 * w;
this.value1 = x2 * w;
result = this.value0;
} else {
result = this.value1;
}
this.generate = !this.generate
return result;
}
function gaussianRandAdj(mean, stddev) {
const value = gaussianRand();
return ((value * stddev) + mean);
}
$(document).ready(function() {
/**
* Pardon the sloppiness. What happens below can be summed as:
*
* 1. Generate a number of normally-distrubted random values.
* 2. Find the minimum and maximum generated value.
* 3. Transform the values on the range [0, width] to fit into our div.
* 3b. At the same time, count how many times a value maps to [0, width]
* 4. Find the index that occured the most so we can place vertically.
* 5. Create the value divs. The x-offset is it's index into finals,
* the y-offset it's relative value compared to the most common index.
*
* Obviously, this is very hastily done and can be improved greatly.
*/
//------------------------------------------------------------------
// Step (1)
//------------------------------------------------------------------
var count = 1000; // # of gaussian values to...