This function produces random values with a natural distribution (bell curve).

The Code

I put the code right up front for those who want it. Copy this into your PHP code. I personally save it in a file called randnorm.inc and use require_once('randnorm.inc') in my common includes section.

// This is a more complicated function that lets you set the median, min, and max
function randnorm($med, $min, $max=null) {
	$ldev = ($med-$min)/9;
	if($max == null) $max = $med+$med-$min;
	$rdev = ($max-$med)/9;
	$range = $max-$min;
	$ld = -2*pow(2*$ldev,2);
	$rd = -2*pow(2*$rdev,2);
	do {
		$x = rand()/getrandmax()*$range+$min;
		if($x<$med) {
			$y = rand()/getrandmax();
			$c = pow(M_E,pow($x-$med,2)/$ld);
		} else {
			$y = rand()/getrandmax();
			$c = pow(M_E,pow($x-$med,2)/$rd);
	} while($y>$c);
	return $x;

// This is a less complicated function that only accepts min and max (it is 0.0 to 1.0 if you omit them)
// The median is always halfway between the min and max, so I call this nd for "normal distribution"
function ndrand($a=null,$b=null) {
	do {
		$x = mt_rand()/mt_getrandmax();
		$y = mt_rand()/mt_getrandmax();
		$c = exp(-pow($x-0.5,2)/(2*pow((1/6),2)));
	} while($y>$c);
	if($a === null) return $x;
	if($b === null) return $x*$a;
	if(is_int($a) && is_int($b)) return floor(($b+1-$a)*$x+$a);
	return ($b-$a)*$x+$a;


If you want a natural distribution around a mean, use:
$RandomValue = randnorm($Mean, $MinValue);
If you have a standard deviation, calculate the minimum value as: $Mean-9*$StdDev.

You can skew the curve to one side by supplying uneven min and max values as:
$RandomValue = randnorm($Median, $MinValue, $MaxValue);
The output will have a natural distribution, but the devations on each side will be uneven. It will have one tail longer than the other.

For the simpler ndrand, no parameters returns a value from 0.0 to 1.0, distributed around 0.5. If you supply one value, the returned value goes from 0.0 to the value you give. If you supply two values, the returned value is limited by the two values. If both values are integers, you get an integer returned. So, the cheat sheet is:
$RandomValue = ndrand(); returns a value from 0.0 to 1.0
$RandomValue = ndrand($max); returns a value from 0.0 to $max
$RandomValue = ndrand($min,$max); returns a value from $min to $max

You've read it. You can't unread it.
Copyright ©1998-2021 C. Shaun Wagner. All rights reserved.