Random, but should not exceed total - php

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

Related

How to Calculate and Get Digit Using Module 11 Algorithm

I'm trying to do a syntax cast where I have a javascript function that calculates the check digit from an input number.
where the variables:
input - is the input value (Example: 200300)
num_digits - is the number of digits (if defined 1, its respective digit will be 7; already defined it 2, its respective digit will be 70. According to the input value)
limit - is the multiplication limit (in my case I need it to be multiplied by/up to 9)
x10 - in this case being true or false, being true the digit will be multiplied by 10
all variables mentioned above refer to my JavaScript function:
function calcDigitMod11(input, num_digits, limit, x10) {
var mult, sum, i, n, digit;
if (!x10) num_digits = 1;
for (n = 1; n <= num_digits; n++) {
sum = 0; mult = 2;
for (i = (input.length - 1); i >= 0; i--) {
sum += (mult * parseInt(input.charAt(i)));
if (++mult > limit) mult = 2;
}
if (x10) {
digit = ((sum * 10) % 11) % 10;
} else {
digit = sum % 11;
if (digit == 10) digit = 'x';
}
input += (digit);
}
return input.substring((input.length - num_digits), num_digits);
}
in short, my big problem is to create this same function in the php syntax
If you print the function's return on the console, passing the following parameters: calcDigitMod11(200300, 1, 9, true); your return must be the check digit
7
giving an applied...
"tried" to convert syntaxes using the same variables, parameters, among others
function calcDigitMod11($input, $num_digits, $limit, $x10) {
$mult; $sum; $i; $n; $digit;
if (!$x10) $num_digits = 1;
for ($n = 1; $n <= $num_digits; $n++) {
$sum = 0; $mult = 2;
for ($i = (strlen($input) - 1); $i >= 0; $i--) {
$sum += ($mult * (int)$input[$i]);
if ((++$mult) > $limit) $mult = 2;
}
if ($x10) {
$digit = (($sum * 10) % 11) % 10;
} else {
$digit = $sum % 11;
if ($digit == 10) $digit = 'x';
}
$input += ($digit);
}
return substr($input, strlen($input) - $num_digits, $num_digits);
}
I wrote an echo calcDigitMod11(200300, 1, 9, true); but it returns the digit to me.
0
I didn't find where the mistaken point x is, I don't know if I'm running away from logic! Here is a table of the JavaScript function of the true digits according to the input value:
calcDigitMod11(200300, 1, 9, true); is return 7
calcDigitMod11(200301, 1, 9, true); is return 5
calcDigitMod11(200302, 1, 9, true); is return 3
calcDigitMod11(200303, 1, 9, true); is return 1
In PHP, you can retrieve characters using index values only for strings. Example:
$str = "98765";
echo $str[1]; // will return 8
If we do the same for integers it will throw a warning.
$num = 98765;
echo $num[1];
Warning: Trying to access array offset on value of type int
To enable errors/warnings in your script, add the below code at the top of your php file
error_reporting(E_ALL);
ini_set('display_errors', '1');
Now, to fix your algorithm, we can use str_split to convert the integer values into an array before using index to extract digits.
<?php
function calcDigitMod11($input, $num_digits, $limit, $x10) {
$mult; $sum; $i; $n; $digit;
if (!$x10) $num_digits = 1;
for ($n = 1; $n <= $num_digits; $n++) {
$sum = 0; $mult = 2;
$input_arr = str_split($input); // Convert string to an array
for ($i = (strlen($input) - 1); $i >= 0; $i--) {
$sum += ($mult * $input_arr[$i]); // Use array to fetch digits
if ((++$mult) > $limit) $mult = 2;
}
if ($x10) {
$digit = (($sum * 10) % 11) % 10;
} else {
$digit = $sum % 11;
if ($digit == 10) $digit = 'x';
}
$input += ($digit);
}
echo "<br/><br/>True Digit=$digit<br/>";
return substr($input, strlen($input) - $num_digits, $num_digits);
}
echo "Output=" . calcDigitMod11(200300, 1, 9, true);
echo "Output=" . calcDigitMod11(200301, 1, 9, true);
echo "Output=" . calcDigitMod11(200302, 1, 9, true);
echo "Output=" . calcDigitMod11(200303, 1, 9, true);
?>
Output:
True Digit=7
Output=7
True Digit=5
Output=6
True Digit=3
Output=5
True Digit=1
Output=4
Working Demo

How can I calculate min, max and average values from random numbers?

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

Unknow output when subtrating result with number

I was trying to subtrat a result output with number am geting unknown result result example 555555 instead of 5 here is my code:
<?php
$txt = "12345678910";
$nu = 2;
$u = 8;
$disp = str_split($txt, $nu);
for($i = 0; $i < $u; $i++) {
$count += count($disp[$i]);
if(strlen($disp[$i]) != $nu)
{
$count = substr($count, 0, 1);
$uu = ($count - 1);
$we =substr($uu, 0, 1);
echo $we;
}
}
?>
thanks for reading and impact in my solutions
This is in answer to removing your errors so it just displays 5.
I seriously have no understanding as to your intentions with this code but to get rid of your errors, you need to refactor things.
Your value of $u is dependant upon the length of $txt and how many digits you set in str_split. Your value of $u is too big as the entries for indexes 6 and 7 do not exist in your array.
1st go ...
<?php
$txt = "12345678910"; // The string of digits
$nu = 2; // How many digits per array
$disp = str_split($txt, $nu); // The array of strings of $nu digits
$u = count($disp); // Calculate the size of $disp - don't guess
$count = 0; // initialise the variable
for ($i = 0; $i < $u; $i++) {
$count += count($disp[$i]); // count($disp[$i]) will always be 1
// Looking for an entry that isn't $nu digits in size
if (strlen($disp[$i]) != $nu) {
$count = substr($count, 0, 1); // Rip off the 1st digit of the index count
$uu = ($count - 1); // decrement it?
echo $uu; // display it
}
}
Another way...
So using foreach is nicer as it takes care of all the hard work.
<?php
$txt = "12345678910";
$nu = 2;
$disp = str_split($txt, $nu);
// DEBUG
var_dump($disp);
$count = 0; // Initialise the variable before we can += it
foreach ($disp as $number) {
$count += 1;
if (strlen($number) != $nu) {
// Taking the index count, getting the 1st digit
$count = substr($count, 0, 1);
// Then subtracting 1 from it
$uu = $count - 1;
echo $uu;
}
}
So this only addresses what you have so it's a bit nicer and without errors ONLY.
Typecasting blindly on the fly in PHP from strings to integers and back again can be a trap.

How do I roll over when doing math on an array of integers?

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

Random Number PHP Confusion

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
}

Categories