The Little Guy Posted February 24, 2009 Share Posted February 24, 2009 Is there a way to generate a random number, but use a "Chance" like scenario? So, lets say I want a random number between 1 and 20, but lets say I only want a 1 in 10 chance if the number being over 5. How could that be achieved? Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/ Share on other sites More sharing options...
Mark Baker Posted February 24, 2009 Share Posted February 24, 2009 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; } ?> Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770645 Share on other sites More sharing options...
The Little Guy Posted February 24, 2009 Author Share Posted February 24, 2009 in my example, I just want a 1 in 10 chance of the number being greater than 5. So if you were to roll a 20 sided die 10 times, on average only one of the numbers would be greater than 5 Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770656 Share on other sites More sharing options...
Phoenix~Fire Posted February 25, 2009 Share Posted February 25, 2009 $odds = rand(1,10); if($odds == 1) $out = rand(6,20); else $out = rand(1,5); Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770738 Share on other sites More sharing options...
cooldude832 Posted February 25, 2009 Share Posted February 25, 2009 $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 Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770740 Share on other sites More sharing options...
The Little Guy Posted February 25, 2009 Author Share Posted February 25, 2009 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? Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770762 Share on other sites More sharing options...
Philip Posted February 25, 2009 Share Posted February 25, 2009 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. Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770764 Share on other sites More sharing options...
Mark Baker Posted February 25, 2009 Share Posted February 25, 2009 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 Quote Link to comment https://forums.phpfreaks.com/topic/146780-chance/#findComment-770947 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.