Jump to content

Chance


The Little Guy

Recommended Posts

Standard random numbers follow a linear distribution.

Are you after a mathematically-based non-linear distribution such as a poisson curve or a gaussian? Or just a simple arbitrary distribution.

 

If the latter, you could create an array based on the probabilities that you want for each value

e.g. $randomArray = array(1,1,1,2,2,3,3,4,4,5,6,7,8,9,10);

Then shuffle the array and take the first value as your random number.

 

If the former, then you may find the following useful:

<?php

define( 'RandomGaussian',			'gaussian' ) ;			//	gaussianWeightedRnd()
define( 'RandomBell',				'bell' ) ;				//	bellWeightedRnd()
define( 'RandomGaussianRising',		'gaussianRising' ) ;	//	gaussianWeightedRisingRnd()
define( 'RandomGaussianFalling',	'gaussianFalling' ) ;	//	gaussianWeightedFallingRnd()
define( 'RandomGamma',				'gamma' ) ;				//	gammaWeightedRnd()
define( 'RandomLogarithmic',		'log' ) ;				//	logarithmicWeightedRnd()
define( 'RandomPoisson',			'poisson' ) ;			//	poissonWeightedRnd()


function mkseed()
{
srand(hexdec(substr(md5(microtime()), -) & 0x7fffffff) ;
}


function random_0_1()
{
//	returns random number using mt_rand() with a flat distribution from 0 to 1 inclusive
//
return (float) mt_rand() / (float) mt_getrandmax() ;
}

function random_PN()
{
//	returns random number using mt_rand() with a flat distribution from -1 to 1 inclusive
//
return (2.0 * random_0_1()) - 1.0 ;
}


function gauss()
{
static $useExists = false ;
static $useValue ;

if ($useExists) {
	//	Use value from a previous call to this function
	//
	$useExists = false ;
	return $useValue ;
} else {
	//	Polar form of the Box-Muller transformation
	//
	$w = 2.0 ;
	while (($w >= 1.0) || ($w == 0.0)) {
		$x = random_PN() ;
		$y = random_PN() ;
		$w = ($x * $x) + ($y * $y) ;
	}
	$w = sqrt((-2.0 * log($w)) / $w) ;

	//	Set value for next call to this function
	//
	$useValue = $y * $w ;
	$useExists = true ;

	return $x * $w ;
}
}

function gauss_ms( $mean,
			   $stddev )
{
//	Adjust our gaussian random to fit the mean and standard deviation
//	The division by 4 is an arbitrary value to help fit the distribution
//		within our required range, and gives a best fit for $stddev = 1.0
//
return gauss() * ($stddev/4) + $mean;
}

function gaussianWeightedRnd( $LowValue,
							 $maxRand,
							 $mean=0.0,
							 $stddev=2.0 )
{
//	Adjust a gaussian random value to fit within our specified range
//		by 'trimming' the extreme values as the distribution curve
//		approaches +/- infinity
$rand_val = $LowValue + $maxRand ;
while (($rand_val < $LowValue) || ($rand_val >= ($LowValue + $maxRand))) {
	$rand_val = floor(gauss_ms($mean,$stddev) * $maxRand) + $LowValue ;
	$rand_val = ($rand_val + $maxRand) / 2 ;
}

return $rand_val ;
}

function bellWeightedRnd( $LowValue,
						 $maxRand )
{
return gaussianWeightedRnd( $LowValue, $maxRand, 0.0, 1.0 ) ;
}

function gaussianWeightedRisingRnd( $LowValue,
								   $maxRand )
{
//	Adjust a gaussian random value to fit within our specified range
//		by 'trimming' the extreme values as the distribution curve
//		approaches +/- infinity
//	The division by 4 is an arbitrary value to help fit the distribution
//		within our required range
$rand_val = $LowValue + $maxRand ;
while (($rand_val < $LowValue) || ($rand_val >= ($LowValue + $maxRand))) {
	$rand_val = $maxRand - round((abs(gauss()) / 4) * $maxRand) + $LowValue ;
}

return $rand_val ;
}

function gaussianWeightedFallingRnd( $LowValue,
									$maxRand )
{
//	Adjust a gaussian random value to fit within our specified range
//		by 'trimming' the extreme values as the distribution curve
//		approaches +/- infinity
//	The division by 4 is an arbitrary value to help fit the distribution
//		within our required range
$rand_val = $LowValue + $maxRand ;
while (($rand_val < $LowValue) || ($rand_val >= ($LowValue + $maxRand))) {
	$rand_val = floor((abs(gauss()) / 4) * $maxRand) + $LowValue ;
}

return $rand_val ;
}

function logarithmic($mean=1.0, $lambda=5.0)
{
return ($mean * -log(random_0_1())) / $lambda ;
}

function logarithmicWeightedRnd( $LowValue,
								$maxRand )
{
do {
	$rand_val = logarithmic() ;
} while ($rand_val > 1) ;

return floor($rand_val * $maxRand) + $LowValue ;
}

function gamma( $lambda=3.0 )
{
$wLambda = $lambda + 1.0 ;
if ($lambda <= 8.0) {
	//	Use direct method, adding waiting times
	$x = 1.0 ;
	for ($j = 1; $j <= $wLambda; $j++) {
		$x *= random_0_1() ;
	}
	$x = -log($x) ;
} else {
	//	Use rejection method
	do {
		do {
			//	Generate the tangent of a random angle, the equivalent of
			//		$y = tan(pi * random_0_1())
			do {
				$v1 = random_0_1() ;
				$v2 = random_PN() ;
			} while (($v1 * $v1 + $v2 * $v2) > 1.0) ;
			$y = $v2 / $v1 ;
			$s = sqrt(2.0 * $lambda + 1.0) ;
			$x = $s * $y + $lambda ;
		//	Reject in the region of zero probability
		} while ($x <= 0.0) ;
		//	Ratio of probability function to comparison function
		$e = (1.0 + $y * $y) * exp($lambda * log($x / $lambda) - $s * $y) ;
	//	Reject on the basis of a second uniform deviate
	} while (random_0_1() > $e) ;
}

return $x ;
}

function gammaWeightedRnd( $LowValue,
						  $maxRand )
{
do {
	$rand_val = gamma() / 12 ;
} while ($rand_val > 1) ;

return floor($rand_val * $maxRand) + $LowValue ;
}

function gammaln($in)
{
$tmp = $in + 4.5 ;
$tmp -= ($in - 0.5) * log($tmp) ;

$ser = 1.000000000190015
		+ (76.18009172947146 / $in)
		- (86.50532032941677 / ($in + 1.0))
		+ (24.01409824083091 / ($in + 2.0))
		- (1.231739572450155 / ($in + 3.0))
		+ (0.1208650973866179e-2 / ($in + 4.0))
		- (0.5395239384953e-5 / ($in + 5.0)) ;

return (log(2.5066282746310005 * $ser) - $tmp) ;
}

function poisson( $lambda=1.0 )
{
static $oldLambda ;
static $g, $sq, $alxm ;

if ($lambda <= 12.0) {
	//	Use direct method
	if ($lambda <> $oldLambda) {
		$oldLambda = $lambda ;
		$g = exp(-$lambda) ;
	}
	$x = -1 ;
	$t = 1.0 ;
	do {
		++$x ;
		$t *= random_0_1() ;
	} while ($t > $g) ;
} else {
	//	Use rejection method
	if ($lambda <> $oldLambda) {
		$oldLambda = $lambda ;
		$sq = sqrt(2.0 * $lambda) ;
		$alxm = log($lambda) ;
		$g = $lambda * $alxm - gammaln($lambda + 1.0) ;
	}
	do {
		do {
			//	$y is a deviate from a Lorentzian comparison function
			$y = tan(pi() * random_0_1()) ;
			$x = $sq * $y + $lambda ;
		//	Reject if close to zero probability
		} while ($x < 0.0) ;
		$x = floor($x) ;
		//	Ratio of the desired distribution to the comparison function
		//	We accept or reject by comparing it to another uniform deviate
		//	The factor 0.9 is used so that $t never exceeds 1
		$t = 0.9 * (1.0 + $y * $y) * exp($x * $alxm - gammaln($x + 1.0) - $g) ;
	} while (random_0_1() > $t) ;
}

return $x ;
}

function poissonWeightedRnd( $LowValue,
							$maxRand )
{
do {
	$rand_val = poisson() / $maxRand ;
} while ($rand_val > 1) ;

return floor($x * $maxRand) + $LowValue ;
}

function linearWeightedRnd( $LowValue,
						   $maxRand )
{
return floor(random_0_1() * ($maxRand)) + $LowValue ;
}	//	function linearWeightedRnd()


function WeightedRnd( $Method,
					 $LowValue,
					 $maxRand )
{
switch($Method) {
	case RandomGaussian			:
		$rVal = gaussianWeightedRnd( $LowValue, $maxRand ) ;
		break ;
	case RandomBell				:
		$rVal = bellWeightedRnd( $LowValue, $maxRand ) ;
		break ;
	case RandomGaussianRising	:
		$rVal = gaussianWeightedRisingRnd( $LowValue, $maxRand ) ;
		break ;
	case RandomGaussianFalling	:
		$rVal = gaussianWeightedFallingRnd( $LowValue, $maxRand ) ;
		break ;
	case RandomGamma			:
		$rVal = gammaWeightedRnd( $LowValue, $maxRand ) ;
		break ;
	case RandomLogarithmic		:
		$rVal = logarithmicWeightedRnd( $LowValue, $maxRand ) ;
		break ;
	case RandomPoisson			:
		$rVal = poissonWeightedRnd( $LowValue, $maxRand ) ;
		break ;
	default						:
		$rVal = linearWeightedRnd( $LowValue, $maxRand ) ;
		break ;
}

return $rVal;
}

?>

Link to comment
https://forums.phpfreaks.com/topic/146780-chance/#findComment-770645
Share on other sites

$odds = rand(1,10);

 

if($odds == 1)

$out = rand(6,20);

else

$out = rand(1,5);

 

 

 

 

 

While that makes sense it technically isn't a pure 1:10 in the end I think (don't quote me but I don't think its true)

 

He wants a 1:10 to be the number 1,2,3,4,5 vs a number 6-20 

I think

Link to comment
https://forums.phpfreaks.com/topic/146780-chance/#findComment-770740
Share on other sites

I think you have it backwards, maybe I am wrong though.

 

if your roll the die (20 sides) 10 times you will get more <5 than you would >5.

 

example...

 

1
4
5
3
1
3
10
4
3
5

 

See there is only one number greater than 5 (a 1:10 ratio)

 

does that make more sense?

Link to comment
https://forums.phpfreaks.com/topic/146780-chance/#findComment-770762
Share on other sites

Just as Mark stated earlier about an array, this site has an example code that is similar to what you are wanting:

http://20bits.com/articles/random-weighted-elements-in-php/

 

However, I think the following would be easiest

you could create an array based on the probabilities that you want for each value

e.g. $randomArray = array(1,1,1,2,2,3,3,4,4,5,6,7,8,9,10);

Then shuffle the array and take the first value as your random number.

Link to comment
https://forums.phpfreaks.com/topic/146780-chance/#findComment-770764
Share on other sites

See there is only one number greater than 5 (a 1:10 ratio)

Was that list of numbers generated using Phoenix~Fire's code? If so, it should match what you're trying to achieve.

 

Out of interest, why do you want this kind of distribution anyway? It's highly unusual

Link to comment
https://forums.phpfreaks.com/topic/146780-chance/#findComment-770947
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.