# Lognormal cumulative distribution function for JavaScript?

Hey everyone!

I'm building a "Deal or No Deal" calculator that estimates the odds of getting a better deal than the one presented. As you can see in the title, I'm looking for a function that will calculate the CDF. For ease's sake, please only post JavaScript code (no C,Perl,BASIC,etc.)

I like Serena
Homework Helper
Hey everyone!

I'm building a "Deal or No Deal" calculator that estimates the odds of getting a better deal than the one presented. As you can see in the title, I'm looking for a function that will calculate the CDF. For ease's sake, please only post JavaScript code (no C,Perl,BASIC,etc.)

Here you go.

Assuming you have mu and sigma as parameters of the log normal distribution (see http://en.wikipedia.org/wiki/Lognormal_distribution), the algorithm is:

Code:
// Get a standard normally distributed number using Box-Muller
double z1 = Math.sqrt(-2 * Math.log(1.0 - Math.random()))
* Math.sin(2 * Math.PI * Math.random());

// Transform the number to the log normal distribution
double x = Math.exp(mu + sigma * z1);

[EDIT]Adjusted the code to prevent a domain-violation of Math.log()[/EDIT]

Code:
// Get a standard normally distributed number using Box-Muller
double z1 = Math.sqrt(-2 * Math.log(1.0 - Math.random()))
* Math.sin(2 * Math.PI * Math.random());

// Transform the number to the log normal distribution
double x = Math.exp(mu + sigma * z1);
[EDIT]Adjusted the code to prevent a domain-violation of Math.log()[/EDIT]

Uh, thanks I guess. Just to be certain you aren't missing anything, this outputs P(X <= x), correct?
EDIT: One more thing: Does the lognormal distribution seem more appropriate for my case than the normal distribution? EDIT: Pardon my asking, but do I need to run this algorithm repeatedly? EDIT: I found another one:

Code:
function rnd_bmt() {
var x = 0, y = 0, rds, c;

// Get two random numbers from -1 to 1.
// If the radius is zero or greater than 1, throw them out and pick two new ones
// Rejection sampling throws away about 20% of the pairs.
do {
x = Math.random()*2-1;
y = Math.random()*2-1;
rds = x*x + y*y;
}
while (rds == 0 || rds > 1)

// This magic is the Box-Muller Transform
c = Math.sqrt(-2*Math.log(rds)/rds);

// It always creates a pair of numbers. I'll return them in an array.
// This function is quite efficient so don't be afraid to throw one away if you don't need both.
return [x*c, y*c];
}

Last edited:
I like Serena
Homework Helper
Uh, thanks I guess. Just to be certain you aren't missing anything, this outputs P(X <= x), correct?
EDIT: One more thing: Does the lognormal distribution seem more appropriate for my case than the normal distribution? EDIT: Pardon my asking, but do I need to run this algorithm repeatedly? EDIT: I found another one: function rnd_bmt()

Oops. No sorry, this does not output P(X <= x).
It outputs a random number x in such a way that its chance matches the log-normal probability distribution.

The other algorithm you found does the same thing as my first line of code calculating z1.
That is, it generates a random number matching the standard normal distribution. It's just a bit more convoluted.

And I don't know yet what you want to use it for, so I can't tell you whether it is appropriate for your case.

To calculate P(X <= x) you'll need another algorithm.

For starters there is a version in the apache commons library you could use:
http://commons.apache.org/math/apidocs/org/apache/commons/math/distribution/NormalDistribution.html [Broken]

If you call it with:
Code:
NormalDistribution.cumulativeProbability((Math.log(x) - mu) / sigma);
you'll get the P(X <= x) for the log-normal distribution.

Last edited by a moderator:
I like Serena
Homework Helper
Here's a function for the cumulative probability and a second one for the log-normal cumulative probability

Code:
double normalCumulativeProbability(double z)
{
double b1 =  0.31938153;
double b2 = -0.356563782;
double b3 =  1.781477937;
double b4 = -1.821255978;
double b5 =  1.330274429;
double p  =  0.2316419;
double c2 =  0.3989423;

if (z >  6.0) { return 1.0; }; // this guards against overflow
if (z < -6.0) { return 0.0; };
double a = Math.abs(z);
double t = 1.0/(1.0+a*p);
double b = c2*Math.exp((-z)*(z/2.0));
double n = ((((b5*t+b4)*t+b3)*t+b2)*t+b1)*t;
n = 1.0-b*n;
if ( z < 0.0 ) n = 1.0 - n;
return n;
}

double lognormalCumulativeProbability(double x, double mu, double sigma)
{
return normalCumulativeProbabilty((Math.log(x) - mu) / sigma);
}