Random generator returning endless duplicates - php

I am trying to create a random string which will be used as a short reference number. I have spent the last couple of days trying to get this to work but it seems to get to around 32766 records and then it continues with endless duplicates. I need at minimum 200,000 variations.
The code below is a very simple mockup to explain what happens. The code should be syntaxed according to 1a-x1y2z (example) which should give a lot more results than 32k
I have a feeling it may be related to memory but not sure. Any ideas?
<?php
function createReference() {
$num = rand(1, 9);
$alpha = substr(str_shuffle("abcdefghijklmnopqrstuvwxyz"), 0, 1);
$char = '0123456789abcdefghijklmnopqrstuvwxyz';
$charLength = strlen($char);
$rand = '';
for ($i = 0; $i < 6; $i++) {
$rand .= $char[rand(0, $charLength - 1)];
}
return $num . $alpha . "-" . $rand;
}
$codes = [];
for ($i = 1; $i <= 200000; $i++) {
$code = createReference();
while (in_array($code, $codes) == true) {
echo 'Duplicate: ' . $code . '<br />';
$code = createReference();
}
$codes[] = $code;
echo $i . ": " . $code . "<br />";
}
exit;
?>
UPDATE
So I am beginning to wonder if this is not something with our WAMP setup (Bitnami) as our local machine gets to exactly 1024 records before it starts duplicating. By removing 1 character from the string above (instead of 6 in the for loop I make it 5) it gets to exactly 32768 records.
I uploaded the script to our centos server and had no duplicates.
What in our enviroment could cause such a behaviour?

The code looks overly complex to me. Let's assume for the moment you really want to create n unique strings each based on a single random value (rand/mt_rand/something between INT_MIN,INT_MAX).
You can start by decoupling the generation of the random values from the encoding (there seems to be nothing in the code that makes a string dependant on any previous state - excpt for the uniqueness). Comparing integers is quite a bit faster than comparing arbitrary strings.
mt_rand() returns anything between INT_MIN and INT_MAX, using 32bit integers (could be 64bit as well, depends on how php has been compiled) that gives ~232 elements. You want to pick 200k, let's make it 400k, that's ~ a 1/10000 of the value range. It's therefore reasonable to assume everything goes well with the uniqueness...and then check at a later time. and add more values if a collision occured. Again much faster than checking in_array in each iteration of the loop.
Once you have enough values, you can encode/convert them to a format you wish. I don't know whether the <digit><character>-<something> format is mandatory but assume it is not -> base_convert()
<?php
function unqiueRandomValues($n) {
$values = array();
while( count($values) < $n ) {
for($i=count($values);$i<$n; $i++) {
$values[] = mt_rand();
}
$values = array_unique($values);
}
return $values;
}
function createReferences($n) {
return array_map(
function($e) {
return base_convert($e, 10, 36);
},
unqiueRandomValues($n)
);
}
$start = microtime(true);
$references = createReferences(400000);
$end = microtime(true);
echo count($references), ' ', count(array_unique($references)), ' ', $end-$start, ' ', $references[0];
prints e.g. 400000 400000 3.3981630802155 f3plox on my i7-4770. (The $end-$start part is constantly between 3.2 and 3.4)
Using base_convert() there can be strings like li10, which can be quite annoying to decipher if you have to manually type the string.

Related

Best method to intersect many arrays

I have a 2 dimensional array ($a), the first dimensional has 600 elements, the second dimension can have from 1k to 10k elements. Something like:
$a[0] = array(4 => true, 10 => true, 18 => true...);
$a[1] = array(6 => true, 10 => true, 73 => true...);
$a[599] = array(106 => true, 293 => true, 297 => true...);
I need to save in a file the $intersection of each of those 600 elements with each other 5x. Something like this:
for ($i=0;$i<=599;$i++) {
for ($j=$i+1;$j<=599;$j++) {
for ($k=$j+1;$k<=599;$k++) {
for ($p=$k+1;$p<=599;$p++) {
for ($m=$p+1;$m<=599;$m++) {
$intersection = array_intersect_key($a[$i], $a[$j], $a[$k], $a[$p], $a[$m]);
}
}
}
}
}
I am using array_intersect_key because its much faster than array_intersect because it's O(n) vs O(n^2).
That code works fine but runs pretty slow. So I made maaany other attempts which runs a little faster, something like:
for ($i=0;$i<=599;$i++) {
for ($j=$i+1;$j<=599;$j++) {
$b = array_intersect_keys($a[$i], $a[$j]);
for ($k=$j+1;$k<=599;$k++) {
$c = array_intersect_keys($b, $a[$k]);
for ($p=$k+1;$p<=599;$p++) {
$d = array_intersect_keys($c, $a[$p]);
for ($m=$p+1;$m<=599;$m++) {
$intersection = array_intersect_key($d, $a[$m]);
}
}
}
}
}
This runs 3x faster than the 1st code, but it's still pretty slow. I also tried creating long binary vectors like 00000011001110... (for each 600 elements) and doing bitwise operations && which works exactly like an intersect, but it's not much faster and uses a lot more memory.
So I am wondering, do you have any breakthrough suggestion? Any mathematical operation, matrix operation... that I can use? I am really tempted to recreate the C+ code of the array_intersect_keys because at every execution it does a lot of things that I dont need, like ordering the arrays before performing the intersection - I dont need that because I already ordered all my arrays before operations start, so that creates a big overhead. But I still dont want to go that route because it's not that simple to create a PHP extension that performs better than the native implementation.
Note: my array $a has all the elements already sorted and the elements in the first dimension that have less elements in the second dimension are positioned first in the array so array_intersect_keys works much faster because that function has to check only until reach the end of the first parameter (which is smaller in size).
EDIT
#user1597430 Again I appreciate all your attention and further explanations you gave me. You made me complete understand everything you said! And after that, I decided to take a shot on my own implementation of your algorithm and I think it is a little bit simpler and faster because I never need to use sort and I also make good use of array keys (instead of values). Feel free to use the algorithm below whenever you want if you ever need it, you already provided me with lots of your time!
After implementing the algorithm below I just realized one thing at the end! I can ONLY start checking the intersections/combinations after all the combinatory phase is done, and after that, I need to run another algorithm to parse the results. To me that's not possible because using 600x1000 takes already a long time and I may very well end up having to use 600x20000 (yeap, 600 x 20k) and I am pretty sure it's gonna take forever. And only after "forever" is that I will be able to check the combinations/intersections result (parse). Do you know a way in such a manner that I can already check the intersections after each computation or not having to wait ALL the combinations be generated? That's pretty sad that after taking almost 6 hours to understand and implement the algorithm below, I just came to the conclusion it wont fit my need. Dont worry, I will accept your answer if no better one come, since you already helped me a lot and I LEARNED A LOT WITH you!
<?php
$quantity_first_order_array = 10;
$quantity_second_order_array = 20;
$a = array();
$b = array();
for ($i=0;$i<$quantity_first_order_array;$i++) {
for ($j=0;$j<$quantity_second_order_array;$j++) {
//I just use `$i*2 + $j*3 + $j*$i` as a way to avoid using `rand`, dont try to make sense of this expression, it's just to avoid using `rand`.
$a['group-' . $i][$i*2 + $j*3 + $j*$i] = true;
$b[$i*2 + $j*3 + $j*$i] = true;
}
}
//echo "aaaa\n\n";var_dump($a);exit();
$c = array();
foreach ($b as $chave1 => $valor1) {
$c[$chave1] = array();
foreach ($a as $chave2 => $valor2) {
if (isset($a[$chave2][$chave1])) {
$c[$chave1][] = $chave2;
}
}
}
foreach ($c as $chave1 => $valor1) {
if (count($c[$chave1]) < 5) {
unset($c[$chave1]);
}
}
//echo "cccc\n\n";var_dump($c);exit();
$d = array();
foreach ($c as $chave1 => $valor1) {
$qntd_c_chave1 = count($c[$chave1]);
for ($a1=0;$a1<$qntd_c_chave1;$a1++) {
for ($a2=$a1 + 1;$a2<$qntd_c_chave1;$a2++) {
for ($a3=$a2 + 1;$a3<$qntd_c_chave1;$a3++) {
for ($a4=$a3 + 1;$a4<$qntd_c_chave1;$a4++) {
for ($a5=$a4 + 1;$a5<$qntd_c_chave1;$a5++) {
$d[$c[$chave1][$a1] . '|' . $c[$chave1][$a2] . '|' . $c[$chave1][$a3] . '|' . $c[$chave1][$a4] . '|' . $c[$chave1][$a5]][] = $chave1;
}
}
}
}
}
}
echo "dddd\n\n";var_dump($d);exit();
?>
Well, I usually don't do this for free, but since you mentioned genetic algos... Hello from Foldit community.
<?php
# a few magic constants
define('SEQUENCE_LENGTH', 600);
define('SEQUENCE_LENGTH_SUBARRAY', 1000);
define('RAND_MIN', 0);
define('RAND_MAX', 100000);
define('MIN_SHARED_VALUES', 5);
define('FILE_OUTPUT', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'out.csv');
# generates a sample data for processing
$a = [];
for ($i = 0; $i < SEQUENCE_LENGTH; $i++)
{
for ($j = 0; $j < SEQUENCE_LENGTH_SUBARRAY; $j++)
{
$a[$i][] = mt_rand(RAND_MIN, RAND_MAX);
}
$a[$i] = array_unique($a[$i]);
sort($a[$i]);
}
# prepares a map where key indicates the number
# and value is a sequence that contains this number
$map = [];
foreach ($a as $i => $array)
{
foreach ($array as $value)
{
$map[$value][$i] = $i;
}
}
ksort($map);
# extra optimization: drop all values that don't have at least
# MIN_SHARED_VALUES (default = 5) sequences
foreach ($map as $index => $values)
{
if (count($values) < MIN_SHARED_VALUES)
{
unset($map[$index]);
}
else
{
# reindex array keys - we need that later for simple
# "for" loops that should start from "0"
$map[$index] = array_values($map[$index]);
}
}
$file = fopen(FILE_OUTPUT, 'w');
# permutation: generates all sequences that share the same $value
foreach ($map as $value => $array)
{
$array_length = count($array);
for ($i = 0; $i < $array_length; $i++)
{
for ($j = $i + 1; $j < $array_length; $j++)
{
for ($k = $j + 1; $k < $array_length; $k++)
{
for ($l = $k + 1; $l < $array_length; $l++)
{
for ($m = $l + 1; $m < $array_length; $m++)
{
# index indicates a group that share a $value together
$index = implode('-', [$array[$i], $array[$j], $array[$k], $array[$l], $array[$m]]);
# instead of CSV export you can use something like
# "$result[$index][] = $value" here, but you need
# tons of RAM to do that
fputcsv($file, [$index, $value]);
}
}
}
}
}
}
fclose($file);
Locally script makes ~6.3 million permutations, that takes ~15s in total, 70% of the time goes to the I/O HDD operations.
You are free to play with the output method (by using linux sort out.csv -o sorted-out.csv on the top of your CSV file or by creating a separate file pointer for each unique $index sequence to dump your results - it's up to you).

Timing attack with PHP

I'm trying to produce a timing attack in PHP and am using PHP 7.1 with the following script:
<?php
$find = "hello";
$length = array_combine(range(1, 10), array_fill(1, 10, 0));
for ($i = 0; $i < 1000000; $i++) {
for ($j = 1; $j <= 10; $j++) {
$testValue = str_repeat('a', $j);
$start = microtime(true);
if ($find === $testValue) {
// Do nothing
}
$end = microtime(true);
$length[$j] += $end - $start;
}
}
arsort($length);
$length = key($length);
var_dump($length . " found");
$found = '';
$alphabet = array_combine(range('a', 'z'), array_fill(1, 26, 0));
for ($len = 0; $len < $length; $len++) {
$currentIteration = $alphabet;
$filler = str_repeat('a', $length - $len - 1);
for ($i = 0; $i < 1000000; $i++) {
foreach ($currentIteration as $letter => $time) {
$testValue = $found . $letter . $filler;
$start = microtime(true);
if ($find === $testValue) {
// Do nothing
}
$end = microtime(true);
$currentIteration[$letter] += $end - $start;
}
}
arsort($currentIteration);
$found .= key($currentIteration);
}
var_dump($found);
This is searching for a word with the following constraints
a-z only
up to 10 characters
The script finds the length of the word without any issue, but the value of the word never comes back as expected with a timing attack.
Is there something I am doing wrong?
The script loops though lengths, correctly identifies the length. It then loops though each letter (a-z) and checks the speed on these. In theory, 'haaaa' should be slightly slower than 'aaaaa' due to the first letter being a h. It then carries on for each of the five letters.
Running gives something like 'brhas' which is clearly wrong (it's different each time, but always wrong).
Is there something I am doing wrong?
I don't think so. I tried your code and I too, like you and the other people who tried in the comments, get completely random results for the second loop. The first one (the length) is mostly reliable, though not 100% of the times. By the way, the $argv[1] trick suggested didn't really improve the consistency of the results, and honestly I don't really see why it should.
Since I was curious I had a look at the PHP 7.1 source code. The string identity function (zend_is_identical) looks like this:
case IS_STRING:
return (Z_STR_P(op1) == Z_STR_P(op2) ||
(Z_STRLEN_P(op1) == Z_STRLEN_P(op2) &&
memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0));
Now it's easy to see why the first timing attack on the length works great. If the length is different then memcmp is never called and therefore it returns a lot faster. The difference is easily noticeable, even without too many iterations.
Once you have the length figured out, in your second loop you are basically trying to attack the underlying memcmp. The problem is that the difference in timing highly depends on:
the implementation of memcmp
the current load and interfering processes
the architecture of the machine.
I recommend this article titled "Benchmarking memcmp for timing attacks" for more detailed explanations. They did a much more precise benchmark and still were not able to get a clear noticeable difference in timing. I'm simply going to quote the conclusion of the article:
In conclusion, it highly depends on the circumstances if a memcmp() is subject to a timing attack.

How can i loop this process more effectively

I have written a little script to automate some calculations for me. It is pretty simple.
1*3=3
2*3=6
3*3=9 and so on. When the answer(product) is more than one digit long I want it to add the digits of the answer.
3*4=12 || 1+2=3.
I want it to automatically add the answer if it is more than one digit no matter how many times adding the answer arrives larger than a single digit.
as in when you reach 13*3=39 || 3+9=12 || 1+2=3
Currently my code does not loop, and i cannot figure out how to make it loop here.
http://screencast.com/t/MdpQ9XEz
Also, it is not adding up more than 2 digit answers see 34*3=102. any help here to allow it infinity addition would be great.
As each line is produced the answers get larger, so it should add as many digits there are in the answer.
here is my code:
$i = 1; //Start with one
function count_digit($number) {
return strlen((string) $number);
};
while($i < 500){
$product = $i * 3; //Multiply set
$number_of_digits = count_digit($product); //calls function to count digits of $sum
if($number_of_digits > 1){ //if $sum has more than one digit add the digits together
$addproduct = strval($product);//seperates the digits of $sum
$ii = 0;
while($ii <= $number_of_digits -1){
$io = $ii + 1;
if($io < $number_of_digits){
$one = intval($addproduct[$ii]);
$two = intval($addproduct[$io]);
$sum = $one + $two;
print($i . ' * 3 = ' .$product. ' || ' .$one. ' + ' .$two. ' = ' .$sum. '<br>');
};$ii++;
};
}else{
Print ($i . ' * 3 = ' .$product.'<br>'); //Print Set
};
$i++; //add one
}
For a start, you might replace the $i=1, while ..., and $i++ into one statement: for ($i=0; $i<500; $i++) {.... - see http://nz1.php.net/manual/en/control-structures.for.php for more information about for loops. It comes out to effectively the same code, but keeps the three parts (initialisation, test, increment counter) together; it makes it clear that they are related, and quicker to understand.
Next I would replace conversion of the number to a string, seeing if the length of the string is greater than one, etc.... with:
while ($product>10) {
$out=0;
while ($product) {
$out+=$product%10;
$product=(integer)($product/10);
}
$product=$out;
}
Note that at no time am I treating a number as a string - I avoid that wherever possible.
In case you are not familiar with it, $something+=$somethingelse is the same as $something=$sometime+$somethingelse, just a shorthand. $out is the running total, and each time around the inner loop (while $product), $out is increased by the rightmost digit (the ones column): $out+=$product%10 - see http://nz2.php.net/operators.arithmetic for more info, then $product is divided by 10 and converted to an integer, so 12 becomes 1.2, then 1, dropping the right-most digit.
Each time the inner loop is complete (all the digits of $product are used up, and $product is 0), the result (in $out) is copied to $product, and then you get back to the outer loop (to see if the sum of all these digits is now less than 10).
Also important is exactly where in each loop you print what. The first part, with the multiplication, is immediately in the '500' loop; the '||' happens once for each time '$product' is reduced to '$out'; the adding of the digits happens inside the innermost loop, with '+' either BEFORE each digit except the first, or AFTER each digit except the last. Since 'all except the last' is easier to calculate ($product>=10, watch those edge cases!), I chose that one.
Also note that, since I'm adding the digits from the right to the left, rather than left-to-right, the addition is reversed. I do not know if that will be an issue. Always consider if reversing the order will save you a lot of work. Obviously, if they NEED to be done in a particular order, then that might be a problem.
The result is:
for ($i=0; $i<500; $i++) {
$product = $i * 3; //Multiply set
print ($i . ' * 3 = ' .$product);
while ($product>10) {
print ' || ';
$out=0;
while ($product>0) {
print ($product%10);
if ($product>=10) {
print " + ";
}
$out+=$product%10;
$product=(integer)($product/10);
}
$product=$out;
print(' = ' .$product);
}
print "<br>";
};
I've decided to add this as a separate answer, because it uses a different approach to answer your question: the least amount of changes to fix the problem, rather than rewriting the code in an easy-to-read way.
There are two problems with your code, which require two separate fixes.
Problem 1: Your code does not add 3 digit (or more) numbers correctly.
If you look carefully at your code, you will notice that you are adding pairs of numbers ($one and $two); each time you add a pair of numbers, you print it out. This means that for the number 102, you are adding 1 and 0, printing out the results, then adding 0 and 2 and printing it out. Look carefully at your results, and you will see that 102 appears twice!
One way to fix this is to use $three and $four (4 digits is enough for 500*3). This is not good programming, because if you later need 5 digits, you will need to and $five, and so forth.
The way to program this is to start with a $sum of zero, then go through each digit, and add it to the sum, thusly:
$ii = 0;
$sum = 0;
while($ii <= $number_of_digits - 1){
$one = intval($addproduct[$ii]);
$sum = $sum + $one;
$ii++;
}
print($i . ' * 3 = ' .$product. ' || ' . $sum . '<br>');
};
The inner if disappears, of course, since it relates to $io, which we are no longer using.
Of course, now you lose your ability to print the individual digits as you are adding them up. If you want those in, and since we don't know in advance how many there are, you would have to keep a record of them. A string would be suitable for that. Here is how I would do it:
$ii = 0;
$sum = 0;
$maths = "";
while($ii <= $number_of_digits-1){
$one = intval($addproduct[$ii]);
if ($maths=="") {
$maths=$one;
} else {
$maths=$maths . " + " .$one;
}
$sum = $sum + $one;
$ii++;
}
print($i . ' * 3 = ' .$product. ' || ' . $maths . " = " . $sum . '<br>');
};
Note the lines with $math in them; there's one at the top, setting it to an empty string. Then, once we've decided on what number we're adding, we add this to $maths. The first time round is a special case, since we don't want "+" before our first digit, so we make an exception - if $maths is empty, we set it to $one; later times around the loop, it's not empty, so we add " + " . $one;
Problem 2: if the result of the addition is more than 1 digit long, go around again. And again, as many times as required.
At this point I would suggest a little refactoring: I would break the print statement into several parts. First the multiplication - that can easily be moved to the top, immediately after the actual multiplication. Printing the <br> can go at the end, immediately before the $i++. This also means you no longer need the else clause - it's already done. This only leaves the ' || ' . $maths . " = " . $sum. This is going to have to happen every time you go through the adding.
Now, replace your if($number_of_digits... with a while($number_of_digits...; this means it goes through as many times as is needed, if it's zero or 100. This does mean that you're going to have to update $product at the end of your loop, with $product = $sum; - put this immediately after the print statement. You will also need to update $number_of_digits; copy the line from the top to the end of the loop.
If you've been following along, you should have:
$i = 1; //Start with one
function count_digit($number) {
return strlen((string) $number);
};
while($i < 500){
$product = $i * 3; //Multiply set
print($i . ' * 3 = ' .$product); // Print basic multiplication
$number_of_digits = count_digit($product); //calls function to count digits of $sum
while ($number_of_digits > 1){ //if $sum has more than one digit add the digits together
$addproduct = strval($product);//seperates the digits of $sum
$ii = 0;
$sum = 0;
$maths = "";
while($ii <= $number_of_digits-1){
$one = intval($addproduct[$ii]);
if ($maths=="") {
$maths=$one;
} else {
$maths=$maths . " + " .$one;
}
$sum = $sum + $one;
$ii++;
}
print(" || " . $maths . " = " . $sum ); // print one lot of adding
$product=$sum;
$number_of_digits = count_digit($product); //calls function to count digits of $sum
};
Print ("<br>"); //go to next line
$i++; //add one
}

Random numbers with rand() and one seed

I have to generate a large number of unique keys. One key should consist of 16 digits. I came up with the following code:
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
function generate_4_digits(){
$randval = rand(100, 9999);
if($randval < 1000){
$randval = '0'.$randval;
}
return (string)$randval;
}
function generate_cdkey(){
return generate_4_digits() . '-' . generate_4_digits() . '-' . generate_4_digits() . '-' . generate_4_digits();
}
srand(make_seed());
echo generate_cdkey();
The result was quite promising, 6114-0461-7825-1604.
Then I decided to generate 10 000 keys and see how many duplicates I get:
srand(make_seed());
$keys = array();
$duplicates = array();
for($i = 0; $i < 10000; $i++){
$new_key = generate_cdkey();
if(in_array($new_key, $keys)){
$duplicates[] = $new_key;
}
$keys[] = $new_key;
}
$keys_length = count($keys);
var_dump($duplicates);
echo '<pre>';
for($i = 0; $i < $keys_length; $i++){
echo $keys[$i] . "\n";
}
echo '</pre>';
On first run I got 1807 duplicates which was quite disappointing. But for my great surprise on each following run I get the same number of duplicates!? When I looked closely at the generated keys, I realized the last 1807 keys were exactly the same as the first ones. So I can generate 8193 without a single duplicate?! This is so close to 2^13?! Can we conclude rand() is suited to generate maz 2^13 unique numbers? But why?
I changed the code to use mt_rand() and I get no duplicates even when generating 50 000 keys.
This is probably more what you're looking for. openssl_random_pseudo_bytes ( int $length [, bool &$crypto_strong ] )
Throw some uniquid() in there.
http://www.php.net/manual/en/function.uniqid.php
This might be something to do with the behaviour of srand. When checking for duplicates you are only running srand once for all 10000 keys. Perhaps srand only produces enough for ~2^13 keys? What PHP version are you using? Since 4.2.0 srand isn't needed any more, but perhaps in if you call it anyway it stops doing it automatically for the rest of the script.

Run A PHP function only 30% of Time

I need help creating PHP code to echo and run a function only 30% of the time.
Currently I have code below but it doesn't seem to work.
if (mt_rand(1, 3) == 2)
{
echo '';
theFunctionIWantCalled();
}
Are you trying to echo what the function returns? That would be
if(mt_rand(1,100) <= 30)
{
echo function();
}
What you currently have echoes a blank statement, then executes a function. I also changed the random statement. Since this is only pseudo-random and not true randomness, more options will give you a better chance of hitting it 30% of the time.
If you intended to echo a blank statement, then execute a function,
if(mt_rand(1,100) <= 30)
{
echo '';
function();
}
would be correct. Once again, I've changed the if-statement to make it more evenly distributed. To help insure a more even distribution, you could even do
if(mt_rand(1,10000) <= 3000)
since we aren't dealing with true randomness here. It's entirely possible that the algorithm is choosing one number more than others. As was mentioned in the comments of this question, since the algorithm is random, it could be choosing the same number over, and over, and over again. However, in practice, having more numbers to choose from will most likely result in an even distribution. Having only 3 numbers to choose from can skew the results.
Since you are using rand you can't guarantee it will be called 30% of the time. Where you could instead use modulus which will effectively give you 1/3 of the time, not sure how important this is for you but...
$max = 27;
for($i = 1; $i < $max; $i++){
if($i % 3 == 0){
call_function_here();
}
}
Since modulus does not work with floats you can use fmod, this code should be fairly close you can substitute the total iterations and percent...
$total = 50;
$percent = 0.50;
$calls = $total * $percent;
$interval = $total / $calls;
$called = 0;
$notcalled = 0;
for($i = 0; $i <= $total; $i++){
if(fmod($i, $interval) < 1){
$called++;
echo "Called" . "\n";
}else{
$notcalled++;
echo "Not Called" . "\n";
}
}
echo "Called: " . $called . "\n";
echo "Not Called: " . $notcalled . "\n";

Categories