Jump to content

Recommended Posts

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

Link to comment
https://forums.phpfreaks.com/topic/153166-how-to-do-randim-increasing-numbers/
Share on other sites

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);
?>

 

 

 

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

 

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

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

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;
}

?>

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

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

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.

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.

 

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.