So lets say I have 2 numbers in decimals (eg .75 and .25). I am trying to make a function that gets these 2 numbers and chooses a "winner" randomly but based on those 2 numbers' percentages. In short terms, I need the .75 number to have a better chance at getting picked then the .25 number (the .25 can still get picked, but it has only a 25% chance). How should I go about doing this?
$prob = array(25, 75);
$total = array_sum($prob);
$rand = mt_rand(1, $total);
var_dump($rand);
foreach ($prob as $i => $p) {
$rand -= $p;
if ($rand <= 0) {
$winner = $i;
break;
}
}
var_dump($winner);
If they don't always add up to 1, this will still work:
$winner = ( (rand(0,1000) / 1000) <= ($first / ($first + $second)) ) ? $first : $second;
$var1 = 25;
$var2 = 75;
$total = $var1 + $var2;
$rand = mt_rand(1, $total);
if($rand <= $var1)
echo("Value one ({$var1}) Wins!");
else
echo("Value two ({$var2}) Wins!");
Something like that should work.
In this simplistic case you could use:
if (rand(0,1000)/1000 <= 0.25)
{
$winner = $first; // 25% number
}
else {
$winner = $second; // 75% number
}
Related
I have the following code:
<?php
echo "<p>Exercise 5:</p>";
echo "Numbers: ";
$random = 0;
while ($random < 10) {
$rand = rand(2, 80);
echo "$rand";
$random = $random + 1;
if ($random < 10) {
echo ", ";
};
}
echo "<br><br>Min value: <br>";
echo "Max value: <br>";
echo "Average value: <br>";
?>
How can I calculate the min, max and average value of the 10 numbers?
$min = min($rand) doesn't work...
$max = max($rand) doesn't work either...
$rand is a single value, minimum of a single value is irrelevant. Min takes an array as parameter (or several values), so save your values in an array, e.g. like this.
$array = array();
while($random < 10) {
$rand = rand(2, 80);
$array[] = $rand;
$random++; // short for random = random + 1
}
echo min($array);
Works also with max.
Moreover, average = sum / count, you have array_sum and count function in PHP, I let you figure out how to do that.
Edit: Augustin is right about division by zero. Consider adding a condition when making a division by a variable.
One solutions thinking in division by zero could be:
$random = 0;
$numbers = array();
while ($random < 10) {
$rand = rand(2, 80);
echo "$rand";
$numbers[] = $rand;
$random ++;
}
$min = min($numbers);
$max = max($numbers);
if($totalNumbers = count($numbers) > 0) {
$average = array_sum($numbers) / count($numbers);
}else{
$average = 0;
}
echo "<br><br>Min value: $min <br>";
echo "Max value: $max <br>";
echo "Average value: $average <br>";
I don't understand why min or max doesn't work, but in this case, you could make a custom max min function:
function customMaxMin($numbers)
{
$max = 0;
$min = 0;
foreach ($numbers as $number) {
$max = $number;
$min = $number;
if ($max > $number) {
$max = $number;
}
if ($min < $number) {
$min = $number;
}
}
return array('max' => $max, 'min' => $min);
}
Alright so I am trying to find out how to get a number that is closer to result
For example
$number_1 = 100
$number_2 = 150
$result = 130
In this case number_2 is 20 away therefore its closer than number_1. Now I could simply substract number_2 and number_1 from result and see what is closer but I dont want to do it since I have to do bunch of if statements to check maybe number_2 is bigger than result and so on...
Question: How do I find out which number is closer to result in a fast & efficient way & how to check if their distance to result is same?
Give this a try:
<?php
$nums = [
100, 150, 200, 225, 6, 17
];
function closestNumber($numToMatch, array $numbers)
{
$distances = [];
foreach ($numbers as $num) {
if ($num == $numToMatch) {
$distances[$num] = 0;
} elseif ($num < $numToMatch) {
$diff = $numToMatch - $num;
$distances[(string)$num] = $diff;
} else {
$diff = $num - $numToMatch;
$distances["$num"] = $diff;
}
}
asort($distances);
$keys = array_keys($distances);
return $keys[0];
}
echo closestNumber(130, $nums);
We create an array of distances, and then calculate and sort them, finally returning the closest match, being the first element in the sorted array. Have a try of it here: https://3v4l.org/SeqZR
Loop through an array:
$number[0] = 100;
$number[1] = 150;
$baseNumber = 130;
for ($i=0;$i < count($number);$i++) {
$difference[$i] = abs($number[$i] - $baseNumber);
}
$index = array_search(min($difference), $difference);
echo $number[$index];
This will give you the value with the smallest difference in the array.
idk maybe that ?
dist_1 = fabs(result - number_1)
dist_2 = fabs(result - number_2)
if there is more than three values :
an asc list
find the index of result (dichotomic search)
check left & right index
This should work -
$number_1 = 100;
$number_2 = 150;
$number_3 = 160;
$number_4 = 170;
$number_5 = 180;
$result = 130;
// A array to store all the elements
$arr = array($number_1, $number_2, $number_3, $number_4, $number_5, $result);
sort($arr); // sort the array in asc
$pos = array_search($result, $arr); // find the result element
if($pos === 0)
{// if element is the first then closest is second
$closest = $arr[1];
}
elseif ($pos === (count($arr) - 1))
{// if last then closest is 2nd last
$closest = $arr[$pos - 1];
}
else
{// calculate the difference and set closest
$prev = $arr[$pos] - $arr[$pos - 1];
$next = $arr[$pos + 1] - $arr[$pos];
$closest = ($prev >= $next) ? $arr[$pos + 1] : $arr[$pos - 1];
}
echo $closest;
Output
150
Working code
This is my code below. The code itself echoes if the sum of three of random numbers equals 100. For now to get a result of 100 as $valuestotal I have to reload the page a lot. But I want to get the result of 100 as $valuestotal every time I reload the page. How can I do this?
I thought it would be possible with a loop in loop. But it gives the same result x times. I want PHP to keep trying different random values, and when it reaches to the value of 100 as $valuestotal, it should echo the $valuestotal...
What I really want is, for example, I want three random numbers to get total of 100, example is 35 and 25 and 50. Or 25 and 15 and 60... the list goes on...
How is this possible?
$values = rand(1, 100);
$values2 = rand(1, 100);
$values3 = rand(1, 100);
$valuestotal = $values + $values2 + $values3;
//
while ($valuestotal === 100)
{
echo $values;
echo '<br>';
echo $values2;
echo '<br>';
echo $values3;
echo "<br>";
echo $valuestotal;
}
One more possible approach. The code is slightly more complex than some of the other answers, but I wanted to add one way that would only need to loop once.
$target = 100;
$n = 3;
while ($n) {
if (1 < $n--) {
$addend = rand(0, $target - ($n - 1));
$target -= $addend;
$addends[] = $addend;
} else {
$addends[] = $target;
}
}
var_dump($addends);
Basically you subtract a random number between 0 and the remainder of the previous subtraction n times until there's only one repetition left, and the remainder is the last piece. $n - 1 is there so that it doesn't randomly subtract too much for there to be enough left for the rest of the repetitions.
You will not need to loop inside of a loop. For example, you could do this:
<?php
$keepChecking = true;
$values = 0;
$values2 = 0;
$values3 = 0;
$valuestotal = 0;
while($keepChecking){
$values = rand(1, 100);
$values2 = rand(1, 100);
$values3 = rand(1, 100);
$valuestotal = $values + $values2 + $values3;
if ($valuestotal === 100){
$keepChecking = false;
}
}
echo $values;
echo '<br>';
echo $values2;
echo '<br>';
echo $values3;
echo "<br>";
echo $valuestotal;
?>
Results may be:
2
37
61
100
Can test here: http://phpfiddle.org/lite
In a while loop, the block will be execute as long as the condition is
true. So you can think, what do you have to execute multiple times, and
when should it stop?
What you need to execute multiple times is the gathering of random
numbers:
while ( ... ) {
# roll dice, save numbers
}
Now this should stop when sum is 100. The condition stated in the loop
must be true for it to run multiple times, so in this sense, it has to
run while the sum is not 100. Here is a key point that you got
reversed. If your condition is false (by chance it will likely be after
first run) then the loop already stopped. You have to run while the sum
is not 100 so that when it is, it won't gather random numbers anymore.
Then you proceed with echoing them.
$valuestotal = 0;
while ($valuestotal != 100) {
$value1 = rand(1, 100);
$value2 = rand(1, 100);
$value3 = rand(1, 100);
$valuestotal = $value1 + $value2 + $value3;
}
echo "$value1<br>$value2<br>$value3<br>$valuestotal";
As an alternative syntax, you could store the values in an array and use
the array_sum() function:
$numbers = [];
while (array_sum($numbers) != 100)
$numbers = [
rand(1, 100),
rand(1, 100),
rand(1, 100),
];
echo join(' + ', $numbers), ' = ', array_sum($numbers);
<?php
$valuesTotal = 0;
while ($valuesTotal != 100){
$value1 = rand(1, 100);
$value2 = rand(1, 100);
$value3 = rand(1, 100);
$valuesTotal = $value1+$value2+$value3;
echo "\$value1 = $value1 :: \$value2 = $value2 :: \$value3 = $value3 :: \$valuesTotal = $valuesTotal";
}
?>
Another way :
<?php
while (true){
$value1 = rand(1, 100);
$value2 = rand(1, 100);
$value3 = rand(1, 100);
$valuesTotal = $value1+$value2+$value3;
echo "\$value1 = $value1 :: \$value2 = $value2 :: \$value3 = $value3 :: \$valuesTotal = $valuesTotal";
if($valuesTotal == 100){
break;
}
}
?>
This should give you an Idea, it may take a fraction of second to complete the script, or it could take forever, depending on your luck!
You need to write the code to be repeatedly executed between the brackets of your loop, not on top of it.
You will need to get only 2 random numbers which sum up to less than 100, than subtract that sum from 100 to get the 3rd random random. This function does just that in a simplistic manner:
function get_three_rand_numbs_sum_hundred(){
$num1 = rand(1, 99); // Get first random number.
$num2 = rand(1, 99); // Get second random number.
$num3 = 0; // Declare variable which will evnetually hold 3rd random number.
/* While the sum of the first 2 random numbers above is more than a 100,
get another random number for Number 2.*/
while(($num1 + $num2) >= 100){
$num2 = rand(1, 99);
}
// Get the 3rd random number by subtracting the sum of the first two from 100.
$num3 = 100 - ($num1 + $num2);
echo "Number 1 : ".$num1."\n";
echo "Number 2 : ".$num2."\n";
echo "Number 3 : ".$num3."\n";
echo "Sum : ".($num3+$num2+$num1)."\n";
}
NOTE: The rand() function treats the max parameter provided to it as an exclusive value, so you should use 99 instead of a 100 since you are certain you do not want 100 from only 1 variable.
Randomise the values inside a loop and each time set a new value to $valuestotal the loop will only stop if $valuestotal = 100.
$valuestotal = 0;
//
while ($valuestotal !== 100) {
echo $values;
echo '<br>';
echo $values2;
echo '<br>';
echo $values3;
echo "<br>";
$values = rand(1, 100);
$values2 = rand(1, 100);
$values3 = rand(1, 100);
echo $valuestotal . '<br>';
$valuestotal = $values + $values2 + $values3;
}
$arr = array();
$count = 53;
$total = 500;
for ($i = 0; $i < $count; $i++)
{
$arr[] = 0;
}
for ($j = 0; $j < $total; $j++)
{
$arr[rand() % $count]++;
}
echo "<pre>";
print_r($arr);
echo "</pre>";
I am assuming that you need to get 3 different random values whose sum is 100
Try This
$total = 100;
$val1 = rand(1,$total);
$val2 = rand(1, ($total-$val1));
$val3 = $total - ($val1 + $val2);
print($val1."\n");
print($val2."\n");
print($val3."\n");
So I am trying to do math on an array of integers while enforcing a maximum integer in each piece of the array. Similar to this:
function add($amount) {
$result = array_reverse([0, 0, 0, 100, 0]);
$max = 100;
for ($i = 0; $i < count($result); ++$i) {
$int = $result[$i];
$new = $int + $amount;
$amount = 0;
while ($new > $max) {
$new = $new - $max;
++$amount;
}
$result[$i] = $new;
}
return array_reverse($result);
}
add(1); // [0, 0, 0, 100, 1]
add(100); // [0, 0, 0, 100, 100]
add(101); // [0, 0, 1, 0, 100]
So what I have above works but it is slow when adding larger integers. I've tried to do this with bitwise shifts and gotten close but I just can't get it to work for some reason. I think I need a third-party perspective. Does anyone have some tips?
The part that is taking up the majority of the time is the while loop. You are reducing the value down repeatedly until you have a sub-100 value. However, using PHP to loop down like that takes an incredible amount of time (a 12-digit integer clocked in at over 20 seconds on my local machine). Instead, use multiplication and division (along with an if). It is magnitudes faster. The same 12-digit integer took less than a second to complete with this code:
function add($amount) {
$result = array_reverse([0, 0, 0, 100, 0]);
$max = 100;
for ($i = 0, $size = count($result); $i < $size; ++$i) {
$int = $result[$i];
$new = $int + $amount;
$amount = 0;
if( $new > $max ) {
$remainder = $new % $max;
// Amount is new divided by max (subtract 1 if remainder is 0 [see next if])
$amount = ((int) ($new / $max));
// If remainder exists, new is the the number of times max goes into new
// minus the value of max. Otherwise it is the remainder
if( $remainder == 0 ) {
$amount -= 1;
$new = $new - ((($new / $max) * $max) - $max);
} else {
$new = $remainder;
}
}
$result[$i] = $new;
}
return array_reverse($result);
}
Also note that I moved your count($result) call into the variable initialization section of the for loop. When it is inside the expression section it gets executed each time the for loop repeats which can also add to the overall time of executing the function.
Also note that with a large math change like this you may want to assert a range of values you expect to calculate to ensure there are no outliers. I did a small range and they all came out the same but I encourage you to run your own.
Use min($max, $number) to get $number limited to $max.
for ($i = 0; $i < count($result); ++$i) {
$result[$i] = min($max, $result[$i] + $amount);
}
rand(1,5)
.. generates random numbers for example: 4 3 2 3 2 (sum is equal 14).
I want the total to NOT exceed x (which is say 5), so in this case, it could be:
1 + 2 + 2 = 5
2 + 3 = 5
and so on ... variable length as long as sum < x
Should I generate a random, check against x, generate another, check again or is there another way?
The most obvious way is just to keep looping and generating a smaller and smaller random number until you're capped out.
$min = 2;
$max = 5;
$randoms = [];
while ($max > $min) {
$max -= ( $rand = rand($min, $max) );
$randoms[] = $rand;
}
Updated for the actual use-case (see comments):
function generateRandomSpend($balance, $maximum = 5, $minimum = 2) {
$amounts = array();
while ($balance) {
// If we can't add any more minimum-spends, stop
if ($balance - $minimum < 0) {
break;
} else {
// Don't generate pointlessly-high values
$maximum = min($balance, $maximum);
$balance -= $amounts[] = rand($minimum, $maximum);
}
}
return $amounts;
}
print_r( $s = generateRandomSpend(10) );
You can also do
echo array_sum( generateRandomSpend(10) );
to get a numeric value of their total spend.
This is also working and give result which you want
<?php
$fixed = 5;
$random = array();
$no = 0;
while(1) {
$number = rand(1,5);
$no +=$number;
if($no > $fixed) {
break;
}
$random[]= $number;
}
?>