Unknow output when subtrating result with number - php

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.

Related

Php binary radix sort implementation

I'm trying to implement a radix sort in binary, because i want to check if the speed of bit shifting operations counterbalance the number of steps required.
My counting sort seems to work, but as soon as i have several passes for the radix sort, the result break.
Any help greatly appreciated.
/*
* bits is to store the value of the current digit for each number in the input array
*/
function countSort(&$arr, $digit) {
$bits = $output = array_fill(0, NB_ELEMS, 0);
$count = [0,0];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$bits[$i] = $bit;
$count[$bit]++;
}
// Cumulative count
$count[1] = NB_ELEMS;
// Rearranging
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = $bits[$i];
$output[$count[$bit] - 1] = $nb;
$count[$bit]--;
}
// Switch arrays
$arr = $output;
}
function radixSort(&$arr, $nb_digits) {
// Do counting sort for every binary digit
for($digit = 0; $digit < $nb_digits; $digit++) {
countSort($arr, $digit);
}
}
$tab = [4,3,12,8,7];
$max_value = max($tab);
$nb_digits = floor(log($max_value, 2)) + 1;
radixSort($tab, $nb_digits);
Ok, thanks to a friend, i found my problem : the counting sort implementation which i use stacks the same digit numbers using the counter as top index, and then decrementing it. And that's ok for counting sort (so one iteration), but it scrambles everything when you use it in radix sort (multiple counting sort iterations).
So i used instead a method in which you shift your counters one time right, which gives you for the n+1 digit your starting point, and then increment it.
And boom you're good to go.
function countSort2(&$arr, $digit) {
$bits = $output = array_fill(0, NB_ELEMS, 0); // output array
$count = [0,0];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$bits[$i] = $bit;
$count[$bit]++;
}
// Cumulative count shifted
$count[1] = $count[0];
$count[0] = 0;
// Rearranging
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = $bits[$i];
$output[$count[$bit]] = $nb;
$count[$bit]++;
}
// Switch arrays
$arr = $output;
}
I also made some tests (1M items, max value 1M, 100 iterations), and a method storing values instead of counting them, and merging thereafter seems twice as fast (function just after that). Anyway, both methods are far under native sort performance.
Any comment appreciated
function byDigitSortArrayMerge(&$arr, $digit) {
$output = array_fill(0, NB_ELEMS - 1, 0); // output array
$bits = array_fill(0, NB_ELEMS - 1, 0); // output array
$by_bit = [[], []];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$by_bit[$bit][] = $nb;
}
$arr = array_merge($by_bit[0], $by_bit[1]);
}

PHP - get random integer using random_int() without repeating and looping

I need to get 50 random numbers out of range 1-100 without repeating. The current way i do is :
$array = array();
while (count($array) <= 50) {
$temp = random_int(1,100);
if (!in_array($temp, $array))
$array[] = $temp;
}
However, the looping is too many because I need to generate for more than 100,000 times.
Is there other ways that I can get a 50 random non-repeating numbers without looping ?
For example:
$number= range(1,100);
$array = array_slice(shuffle($number),0,50);
I can't use shuffle because it uses pseudo random number.
Is there other ways to achieve what I need, or ways that could shorten time.
pre fill a array of numbers and pick from them, and then remove it.
it prevents the unnecessary random generations you have
$numbers = [];
for ($i = 1; $i <= 100; $i++) {
$numbers[] = $i;
}
$randomNumbers = [];
for ($i = 1; $i <= 50; $i++) {
$r = rand(0, count($numbers) - 1);
$randomNumbers[] = $numbers[$r];
array_splice($numbers, $r, 1);
}
This would be my approach:
This gives you 50 numbers in any case, and they are defenitely different from each other. PLUS: you dont have to prefill some other array:
$start = microtime(true);
for($i = 0; $i <= 100000; $i++){
$arr = [];
while(sizeof($arr) < 50){
$num = rand(1, 100);
$arr[$num] = $num;
}
if(array_unique($arr) !== $arr || sizeof($arr) !== 50 ){
print("FAIL");
}
//print(array_unique($arr) == $arr ? "true" : "false");print("<br>");
//print(sizeof($arr));print("<br>");
//print_r(array_count_values ($arr));print("<br>");
//print_r($arr);print("<br>");
}
$time_elapsed_secs = microtime(true) - $start;
print($time_elapsed_secs);print("<br>");
Running this 100000 times takes about 0.4sec for me.
The actual generation is done in this part:
$arr = [];
while(sizeof($arr) < 50){
$num = rand(1, 100);
$arr[$num] = $num;
}
We can do in 2 steps:
$x = 0;
$arr = [];
while($x < 50){
$tmp = rand(1, 100);
if(!in_array($tmp, $arr)){
$arr[] = $tmp;
$x++;
}
}

PHP: Getting random combinations to specified input

I am trying to display possibilities for additions of specific numbers but have not been getting the right results.
<?php
$num3 = 20;
$set = null;
$balance = $num3;
$dig = mt_rand(1,5);
for($i = $balance; $i > 0; $i -= $dig ){
echo $dig.'<br>';
if($i < 1){
$set .= $i;
$balance = 0;
}
else{
$set .= $dig.'+';
$dig = mt_rand(1,5);
}
}
echo $set.'='.$num3;
?>
Here are some of the outputs:
2+5+1+4+5+3+=20
1+4+3+5+3+=20
3+1+1+2+3+4+4+1+3+=20
Appreciate any pointers. Thank in advance...
Ok, even though the requirement isn't completely clear, here's an approach:
(edit: demonstrating prevention of endless loop)
$max_loops = 1000;
$balance = 20;
$found = [];
while($balance > 0 && $max_loops-- > 0) {
$r = mt_rand(1, 5);
if ($balance - $r >= 0) {
$found[] = $r;
$balance -= $r;
}
}
echo implode(' + ', $found) . ' = '.array_sum($found);
Note: This code has a small risk of getting caught in an endless loop... though it's doubtful that it'll ever happen :)
Edit: Now the loop contains a hard-limit of 1000 iterations, after which the loop will end for sure...
To provoke an endless loop, set $balance = 7 and modify mt_rand(4, 5).
You can use a recursive function for this:
function randomAddends($target, $maxAddend = 5, $sum = 0, $addends = [])
{
// Return the array of addends when the target is reached
if ($target <= $sum) {
return $addends;
}
// generate a new random addend and add it to the array
$randomAddend = mt_rand(1, min($maxAddend, $target - $sum));
$addends[] = $randomAddend;
// make the recursive call with the new sum
return randomAddends($target, $maxAddend, $sum + $randomAddend, $addends);
}

Can't get List() function to working with array

Here is my simple code and i'm not able to understand why and how...
$len = 5; // total number of numbers
$min = 1; // minimum
$max = 90; // maximum
$range = array(); // initialize array
foreach (range(0, $len - 1) as $i) {
while(in_array($num = mt_rand($min, $max), $range));
//$range[] = $num;
list($br1, $br2, $br3, $br4, $br5) = $range;
}
print_r($range);
//echo $br1." ".$br2." ".$br3." ".$br4." ".$br5;
Hope in your help...! Thanks!
Should be written as:
<?php
$len = 5; // total number of numbers
$min = 1; // minimum
$max = 90; // maximum
$range = array(); // initialize array
foreach (range(0, $len - 1) as $i) { // you need to repeat the loop $len times
// get a new random number in the given range and assign it to $num,
// do it until the generated number is unique (not present in $range)
// the loop body is empty, as all the action happens inside its condition
while(in_array($num = mt_rand($min, $max), $range));
// append the random number to array
$range[] = $num;
}
list($br1, $br2, $br3, $br4, $br5) = $range;
echo $br1." ".$br2." ".$br3." ".$br4." ".$br5;
Demo.
The existing version of your code never updates $range variable (the corresponding line is commented out for some reason), that's why it doesn't work.
You need simple modification in your code.Your are assign list in side loop.But which is put out site of loop. And your variable range array are need commented
$len = 5; // total number of numbers
$min = 1; // minimum
$max = 90; // maximum
$range = array(); // initialize array
foreach (range(0, $len - 1) as $i) {
while(in_array($num = mt_rand($min, $max), $range));
$range[] = $num;
}
list($br1, $br2, $br3, $br4, $br5) = $range;
print_r($br1);
print_r($br2);
//echo $br1." ".$br2." ".$br3." ".$br4." ".$br5;

Random, but should not exceed total

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

Categories