Jump to content

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

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • 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.