richarro1234 Posted April 8, 2009 Share Posted April 8, 2009 Hello there, What im after is to be able to set (in a database) 2 prices for an item (a min. and a max.) and have some php code randomly select a price between those to numbers, but not too far apart in the oppisite direction. So for example, say i have a bank, max price of 10,000,000 min price of say 4,000,000. i would start it off at 7mil (just because its in between the 2 numbers) what i would like is to have the price either go up or go down from that 7 million, but obviously not exceed the min/max price. so say it starts at 7mill, i would like it to eaither randomly go up to 8, or 9, or even 10, then it either (still at random) stay at 10mill or drop to something like 8mill. not drop too low, like to 4mill. but gradually increase and decrease each time, the time it changes will either be every 20 mins or every 30 mins, or maybe every hour. How can i go about doing such a task? Thanks for you help, if you have any questions or i didnt explain clearly enough then please ask and i will be happy to answer. Thanks Rich Quote Link to comment Share on other sites More sharing options...
rhodesa Posted April 8, 2009 Share Posted April 8, 2009 well...you need to decide what the "not too much is" by the sounds of it, it's about half the difference of the min/max. here is an example...you will need to modify it to fit your specific needs though: <?php session_start(); $value = &$_SESSION['value']; $min = 4000000; $max = 10000000; $change_factor = ($max - $min) / 2; //How much it can go up/down by if(!isset($value)) $value = ($max + $min) / 2; //Here is our starting point //Set the max the new value can be $rand_max = $value + $change_factor; if($rand_max > $max) $rand_max = $max; //Set the min the new value can be $rand_min = $value - $change_factor; if($rand_min > $min) $rand_min = $min; //Get the new value $value = rand($rand_min,$rand_max); print number_format($value); ?> Quote Link to comment Share on other sites More sharing options...
richarro1234 Posted April 8, 2009 Author Share Posted April 8, 2009 Thanks for the quick response a few questions about the code you provided. How can i make it so that its only whole numbers (to the nearest million)? $change_factor = ($max - $min) / 2; //How much it can go up/down by Is that the bit to stop it from dropping from 10m to 4m? (gradual increase/decrease in price) How would i change it to only change at certain times? (every 30 mins or so) rather then every page refresh? Basically this is like a stock market, buy low and sell high. Thanks Rich Quote Link to comment Share on other sites More sharing options...
rhodesa Posted April 8, 2009 Share Posted April 8, 2009 How can i make it so that its only whole numbers (to the nearest million)? um...you can try it with a min of 4 and 10, then multiply by a million when printing $change_factor = ($max - $min) / 2; //How much it can go up/down by Is that the bit to stop it from dropping from 10m to 4m? (gradual increase/decrease in price) yes, that sets how much it changes by How would i change it to only change at certain times? (every 30 mins or so) rather then every page refresh? so, for the example i just put the value in the session cus it was easy. you will need to store it in a DB or file somewhere. then, either track when it was changed last, and only change it if it's more then 30 minutes old...or setup a scheduled task/cronjob to run every 30 minutes and change it Quote Link to comment Share on other sites More sharing options...
richarro1234 Posted April 8, 2009 Author Share Posted April 8, 2009 Well all the information will be stored in a db anyway, to make things easier to change if need be. Thanks for the help, i done what you said and changed it to 4,10 and multiplied by 1mill at the end and it works fine now thanks, onlything is it still drops below 4mill and still abit of a dramatic drop (sometimes from 10-6) but with a bit of editing im sure i can get that sorted. P.S what is "value" for? what does it do? thanks for the help, will post if i have any more questions Thanks Rich Quote Link to comment Share on other sites More sharing options...
Mark Baker Posted April 8, 2009 Share Posted April 8, 2009 Looks like you don't want a simple linearly distributed random number but a random with a poisson or gaussian distribution: <?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 Share on other sites More sharing options...
richarro1234 Posted April 8, 2009 Author Share Posted April 8, 2009 thanks for that mark. i tried to copy and paste it into a page so that i can see what it looks like on a website, but it came up with loads of errors and took up about 1800 lines. Rich Quote Link to comment Share on other sites More sharing options...
richarro1234 Posted April 8, 2009 Author Share Posted April 8, 2009 mark, the one you posted doesnt do anything, it just shows a white screen? not sure what its meant to show. Quote Link to comment Share on other sites More sharing options...
Psycho Posted April 8, 2009 Share Posted April 8, 2009 Rhodesa's code will work fine for a single pass, but will have problems on subsequent passes without accounting for the value not being in the middle of the range. From your description the min/max values do not change each time the number is processed. I think you need a function where you can pass those variables. Here is a function that I think does what you ask. I also included some code at the end to validate if it is what you want. The functin takes four inputs which should be self explanatory <?php function changeValue($current, $min, $max, $step) { //Determine the direction of movement if($current==$max) { $direction = -1; } else if($current==$min) { $direction = 1; } else { $direction = (rand(0,1)==1)?1:-1; } //Determine the maximum range to the min or max based on direction $rangeToEnd = ($direction==1) ? ($max-$current) : ($current-$min); //Detemine the maximum chnage which will be the minimum of $rangeToEnd or 1/2 the (max-min) $maxChange = floor(min($rangeToEnd, (($max-$min)/2))/$step); //Get a random change value $change = rand(1, $maxChange); //Apply change to current and return the value $newValue = ($current + ($change * $step * $direction)); return $newValue; } //Test the code. $value = 7000000; echo "Start Value: ".number_format($value)."<br><br>"; //Run function ten times to test the output for ($i = 0; $i<9; $i++) { $value = changeValue ($value, 4000000, 10000000, 1000000); echo "Step $i: ".number_format($value)."<br>"; } ?> The output of that would look something like this: Start Value: 7,000,000 Step 1: 5,000,000 Step 2: 6,000,000 Step 3: 7,000,000 Step 4: 5,000,000 Step 5: 4,000,000 Step 6: 6,000,000 Step 7: 9,000,000 Step 8: 7,000,000 Step 9: 8,000,000 Step 10: 6,000,000 Quote Link to comment Share on other sites More sharing options...
richarro1234 Posted April 8, 2009 Author Share Posted April 8, 2009 Thanks mjdamato, that works great, what about if all the prices are set in a DB? so the max and min prices are in the DB, along with some other properties to help change the price (each item will have unique properties which will also help influence the price changes.) Thanks Rich Quote Link to comment Share on other sites More sharing options...
Psycho Posted April 9, 2009 Share Posted April 9, 2009 what about if all the prices are set in a DB? so the max and min prices are in the DB, along with some other properties to help change the price (each item will have unique properties which will also help influence the price changes.) Um, query the database for the values. Run them through the function to generate the new values, and put them back in the DB. Quote Link to comment Share on other sites More sharing options...
Mark Baker Posted April 9, 2009 Share Posted April 9, 2009 mark, the one you posted doesnt do anything, it just shows a white screen? not sure what its meant to show. The code I posted was a set of functions, not a working script to display anything: if there were any errors, I'd appreciate knowing exactly what they were. While it's pretty old code that I haven't looked at in a long while (it was written for PHP4, which shows how old it is), but it works perfectly for me (with one exception in the poissonWeightedRnd() function where $x should be $rand_val). I have errorsetting at (E_ALL | E_STRICT) and I don't get any errors at all. here's a simple script to test the functions and show what they do: function testRandomDistribution($method,$heading) { $minValue = 0; $maxValue = 32; $loopCount = 10000; // Initialize the results array $resultArray = array_fill($minValue,$maxValue+1,0); // Generate 1000 random numbers for ($x = 0; $x < $loopCount; $x++) { // Store the distribution of values in $resultArray $value = (string) WeightedRnd( $method, $minValue, $maxValue); if ($value != intval($value)) { // ignore non-integer results $x--; } else { $resultArray[$value]++; } } echo '<h1>'.$heading.'</h1>'; echo '<table>'; for ($i = $minValue; $i <= $maxValue; $i++) { echo '<tr><td align="right">'.$i.'</td>'; echo '<td align="left">'.str_repeat('*',$resultArray[$i] / 10).'</td></tr>'; } echo '</table>'; } testRandomDistribution(NULL, 'linear' ) ; testRandomDistribution(RandomGaussian, 'gaussian' ) ; testRandomDistribution(RandomBell, 'bell' ) ; testRandomDistribution(RandomGaussianRising, 'gaussianRising' ) ; testRandomDistribution(RandomGaussianFalling, 'gaussianFalling' ) ; testRandomDistribution(RandomGamma, 'gamma' ) ; testRandomDistribution(RandomLogarithmic, 'log' ) ; testRandomDistribution(RandomPoisson, 'poisson' ) ; This uses each different method to generate 10000 random numbers between 1 and 32, then displays the distribution of those numbers in a simple chart on screen. Quote Link to comment Share on other sites More sharing options...
richarro1234 Posted April 9, 2009 Author Share Posted April 9, 2009 hey thanks for that just lookin at how to take it apart and use it for what im after Rich Quote Link to comment 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.