Run A PHP function only 30% of Time - php

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

Related

Random generator returning endless duplicates

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.

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
}

PHP code is taking very much time in executing when handling large number

This is a simple program to find prime numbers which check for the division of a number at later stage.
I tried to short it by initially taking the integer square root of the number to break down the complexity. But still it is taking very much time in executing the script. What other changes I can implement in my code to decrease the execution time( I already set the max execution time to 5 min)
<?php
error_reporting(E_ALL);
$num = 600851475143;
//$sqrt_num = (int)sqrt($num);
for( $j = 2; $j <= $num; $j++ )
{
for( $k = 2; $k < $j; $k++ )
{
if( $j % $k == 0 )
{
break;
}
}
if( $k == $j )
{
//echo "Prime Number : ", $j, "<br>";
if( $num % $j == 0 )
{
echo "Prime number : ", $j, "<br>";
}
}
}
EDIT Just commented the line for sqrt as this seems to be in correct..but still the loop is taking much time.
One way to improve execution time of your code would be this:
$num = 1000;
for($j = 2; $j <= $num; $j++)
{
$cond = sqrt($j);
for($k = 2; $k <= $cond; $k++)
{
if($j % $k == 0)
{
break;
}
}
if($k > $cond)
{
echo 'Prime number: ' . $j . '<br>';
}
}
But there is no need to calculate prime numbers from the begining each time. You can remember every 30 seconds or so where you were, save the result to a database, file, or an array, and then restart the script, which should the continue from where it stopped.
The best way to reduce this code execution time is by removing it.
It's unnecessary to calculate every prime number each time you run this- they are not going to be changing any time soon.
Run it once, write it to a file or database and use that when you need it.
I'd personally put it in an array for later use.
Here's the basic algorithm for factoring by trial division; I don't know PHP, so I'll just give pseudocode:
function factors(n)
f, fs := 2, []
while f * f <= n
while n % f == 0
append f to fs
n := n / f
f := f + 1
if n > 1 append n to fs
return fs
There are better ways than that to find the factors of a number, but even that simple method should be sufficient for the Project Euler problem you are trying to solve; you should have a soluion in less than a second. When you're ready for more programming with prime numbers, I modestly recommend this essay at my blog.

PHP why is continue n slower than using break

Please consider the following code:
$start = microtime();
for($i = 2; $i < 100; $i++)
{
for($y = 2; $y <= sqrt($i); $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
continue 2;
}
}
echo $i.',';
}
echo "\nFinished in " . (microtime() - $start);
Given that the above code effectively uses continue 2 to break the inner loop and skip any code post the inner loop, why does the following code on average execute faster when it appears to do more:
$start = microtime();
for($i = 2; $i < 100; $i++)
{
$flag = true;
for($y = 2; $y <= sqrt($i); $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
$flag = false;
break;
}
}
if($flag === true) echo $i.',';
}
echo "\nFinished in " . (microtime() - $start);
Thanks for any input.
_____ Update ____________
Thanks for the feedback but we seem to have missed the point. Regardless of if this is good programming practice I was trying to understand why the performance difference (which is tiny but consistent) is not within the bias I expected.
The passing of true to microtime seems insignificant as both samples are measured using the same method with the same overhead and the same inaccuracy.
More than one run was tested, as implied by use of the word average.
Just for illustration please consider the following small samples using microtime(true) which shows the same pattern as using microtime().
I know this is a small sample but the pattern is quite clear:
Continue
0.00037288665771484
0.00048208236694336
0.00046110153198242
0.00039386749267578
0.0003662109375
Break
0.00033903121948242
0.00035715103149414
0.00033307075500488
0.00034403800964355
0.00032901763916016
Thanks for looking, and thanks for any further feedback.
______ UPDATE Further investigation ____________
Interestingly if the echo statements are removed from the code the continue performs faster, with the echo statements in place break is faster.
Please consider the following code sample, and consider that the results are in conflict dependant on if the echo statements are removed or not:
<?php
$breakStats = array();
$continueStats = array();
ob_start();
for($i = 0; $i < 10000; $i++)
{
$breakStats[] = doBreakTest();
$continueStats[] = doContinueTest();
}
ob_clean();
echo "<br/>Continue Mean " . (array_sum($continueStats) / count($continueStats));
echo "<br/>Break Mean " . (array_sum($breakStats) / count($breakStats));
function doBreakTest()
{
$start = microtime(true);
for($i = 2; $i < 100; $i++)
{
$flag = true;
$root = sqrt($i);
for($y = 2; $y <= $root; $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
$flag = false;
break;
}
}
}
if($flag === true) echo $i . '';
return microtime(true) - $start;
}
function doContinueTest()
{
$start = microtime(true);
for($i = 2; $i < 100; $i++)
{
$root = sqrt($i);
for($y = 2; $y <= $root; $y++)
{
if($i%$y != 0)
{
continue;
}
else
{
echo $i . '';
continue 2;
}
}
}
return microtime(true) - $start;
}
Echo statements present :
Continue Mean 0.00014134283065796
Break Mean 0.00012669243812561
Echo statements not present :
Continue Mean 0.00011746988296509
Break Mean 0.00013022310733795
Note that by removing the echo statement from the break and flag test we also remove the ($flag === true) check, so the load should reduce, but continue in this case still wins. W
So in a pure continue n versus break + flag scenario, it appears that continue n is the faster contstruct. But add an equal number of identical echo statements, and the continue n performance flags.
This makes sense to me logically that continue n should be faster, but I would have expected to see the same with the echo statements present.
This is clearly a difference in the generated opcodes, and the position of the echo statement (inner loop vs outer loop) does anyone know a way of seeing the opcodes generated? This I suppose is ultimatley what I need as I am trying to understand what is happening internally.
Thanks :)
Yes, first one is bit faster. It's because it just jumps out on continue 2 and prints $i.
2nd example has more job to do... assign value to $flag variable, jumps out of loop, checks $flag's value, checks $flag's type (compares too) and then prints out $i. It's bit slower (simple logic).
Anyways, has it any purpose?
Some of my results for comparing
0.0011570 < 0.0012173
0.0011540 < 0.0011754
0.0011820 < 0.0012036
0.0011570 < 0.0011693
0.0011970 < 0.0012790
Used: PHP 5.3.5 # Windows (1000 attempts; 100% first was faster)
0.0011570 < 0.0012173
0.0005000 > 0.0003333
0.0005110 > 0.0004159
0.0003900 < 0.0014029
0.0003950 > 0.0003119
0.0003120 > 0.0002370
Used: PHP 5.3.3 # Linux (1000 attempts; 32% first : 68% second was faster)
0.0006700 > 0.0004863
0.0003470 > 0.0002591
0.0005360 > 0.0004027
0.0004720 > 0.0004229
0.0005300 > 0.0004366
Used: PHP 5.2.13 # Linux (1000 attempts; 9% first : 91% second was faster)
Sorry, I don't have any more servers for testing :) Now I think it mostly depends of hardware (and maybe depends of OS too).
Generally: It proves only that Linux server is faster than one run at Windows :)
The continue 2 version is slightly faster for me. But these aren't the types of things you generally need to concern yourself with. Consider:
for($y = 2; $y <= sqrt($i); $y++)
Here you are calculating the sqrt on every iteration. Just changing that to:
$sqrt = sqrt($i);
for($y = 2; $y <= $sqrt; $y++)
will give you a much better improvement than switching between two nearly identical loop styles.
The continue 2 should be used if you find that it's easier for you to understand. The computer doesn't really care.
To address your update regarding looking at opcodes, see:
http://pecl.php.net/package/vld
php -d vld.active=1 -d vld.execute=0 -f foo.php

The largest prime factor with php

I wrote a program in PHP to find the largest prime factor. I think it is quite optimized, because it loads quite fast. But, there is a problem: it doesn't count the prime factors of very big numbers. Here is the program:
function is_even($s) {
$sk_sum = 0;
for($i = 1; $i <= $s; $i++) {
if($s % $i == 0) { $sk_sum++; }
}
if($sk_sum == 2) {
return true;
}
}
$x = 600851475143; $i = 2; //x is number
while($i <= $x) {
if($x % $i == 0) {
if(is_even($i)) {
$sk = $i; $x = $x / $i;
}
}
$i++;
}
echo $sk;
The largest non-overflowing integer in PHP is stored in the constant PHP_INT_MAX.
You won't be able to work with integers larger than this value in PHP.
To see all of PHP's predefined constants, just use:
<?php
echo '<pre>';
print_r(get_defined_constants());
echo '</pre>';
?>
PHP_INT_MAX probably has a value of 2,147,483,647.
To handle numbers of arbitrary precision in PHP, see either the GMP or BC Math PHP extensions.
You should read about Prime testing and Sieving.
In particular, you don't need to test whether each of your divisors is prime.
Something like the following would be faster.
while($i <= $x)
{
while ($x % $i == 0)
{
$sk = $i;
$x = $x / $i;
}
$i++;
}
You can also stop your outer loop when $i reaches sqrt($x), and if you haven't found a divisor yet then you know $x is prime.
Well, every language has it's own (while usually same) limitations, so if you exceed this php's limit, you can't get any higher. Max Integer is 9E18.

Categories