for($i=0;$i<$num;$i++) {
if($i==even) $hilite="hilite";
dothing($i,$hilite);
}
This is basically what I want to accomplish.
What is the most efficient way to determine if $i is even?
I know I could check if half == mod 2 ... but that seems a little excessive on the calculations? Is there a simpler way?
if ($i % 2 == 0)
The already mentioned % 2 syntax is most used, and most readable for other programmers. If you really want to avoid an 'overhead' of calculations:
for($i = 0, $even = true; $i < $num; $i++, $even =! $even) {
if($even) $hilite = "hilite";
dothing($i,$hilite);
}
Although the assignment itself is probably more work then the '%2' (which is inherently just a bit-shift).
It doesn't get any simpler than $i % 2 == 0. Period.
Change the i++ in the loop statement to i+=2, so that you only examine even values of i?
Typically, a number is odd if it's LSB (Least Significant Bit) is set. You can check the state of this bit by using the bitwise AND operator:
if($testvar & 1){
// $testvar is odd
}else{
// $testvar is even
}
In your code above, a more efficient way would be to have $i increment by 2 in every loop (assuming you can ignore odd-values):
for($i=0;$i<$num;$i+=2){
// $i will always be even!
}
Related
So I am trying to optimize a piece of php code that basically runs the same operations on two different datasets, based on user input. What would be a better and more optimized approach?
//$input = //user input
//$a = [1,2,3 .....];
//$b = [a,b,c .....];//both are same length - n
case 1 :
for($i =0; $i<n; $i++) {
if($input == 'a')
//doSomething with $a[i] - code here
else
//doSomething with $b[i] - code here
}
case 2 :
if($input == 'a') {
for($i =0; $i<n; $i++) {
//doSomething with $a[i] - code here
}
}
else {
for($i =0; $i<n; $i++) {
//doSomething with $b[i] - code here
}
}
case 3 :
if($input == 'a') {
for($i =0; $i<n; $i++) {
doSomething($a[i]);
}
}
else {
for($i =0; $i<n; $i++) {
doSomething($b[i]);
}
}
the operation is same in all cases
Better is always difficult to quantify, but if you want to do exactly the same processing on the inputs, just picking the one dataset depending on the input, you may be better off just setting an input array and just processing that...
if($input == 'a')
$dataset = $a;
else
$dataset = $b;
foreach ( $dataset as $dataItem ) {
//doSomething data code here
}
This might not really be the answer you're looking for, but honestly, I would just go for whatever conveys the actual use case the best and not try to optimize too much.
Performance-wise, unless the operation that checks the $input takes a lot of time (orders of magnitude more than a simple comparison), or if the operation on $dataset is very short (comparable to the input check), it simply won't matter.
Assuming $input does not change while you're processing your dataset, I'd go for case three. You're making it clear that it is the same operation, and the only difference between the different if branches is the dataset you're working with. If you're familiar with ternary operators, I'd even use this:
for($i = 0; $i < n; $i++) {
doSomething(($input == $a) ? $a[i] : $b[i]);
}
I'd take code readability over micro-optimizations any day, as long as you don't actually have performance issues with this piece of code.
As a bonus, have a read at this question about optimization: https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil
I am running a for loop 10 times in order to populate data in a data table. In doing this, I wanted to use number_format in order to format the numbers. However, when I apply the number_format the For loop for some reason runs one additional time.
It works just fine when I exclude the number_format. Can anyone explain why this happens?
<?php
foreach($data['data'] as $result) {
For ($n = 0; $n <= 10; $n++){
echo "<td>";
echo number_format($result[$n], 0, ".", ",");
echo "</td>";
}
}
?>
TL;DR: Your loop will always run an additional time. Assuming that there are no errors in your number_format function call, all you have to do to get this to run 10 times is change your code to for($n = 0; $n < 10; n++). Note the use of < and not <=.
For loops are really just syntactical sugar for while loops. The statement for(initial_statement; bound_condition; loop_statement) { code; } is equivalent to
initial_statement;
while(bound_condition) {
code;
loop_statement;
}
Which, functionally, is equivalent to
initial_statement;
while(true) {
code;
loop_statement;
if(!bound_condition) break;
}
This means that if you want a loop to run, say, 2 times, and you write for($i = 0; $i <= 2; $i++) your code will loop as follows:
$i = 0
i++; (i now equals 1)
i <= 2 (condition is true, so continue)
$i = 1
i++; (i now equals 2)
i <= 2 (condition is true, so continue)
$i = 2
i++; (i now equals 3)
i <= 2 (condition is FALSE, so break)
Using the <= operator when your control variable starts at 0 causes an extra iteration to occur, since there are three integer values of i such that 0 <= i <= 2 (0, 1, and 2). To ensure that there are only two iterations, use the < operator, and now the loop will only be executed for values in the domain 0 <= i < 2 (0 and 1).
If you are still bent on using the <= operator and are fine with a non-zero-based iteration count, then you can simply change the initial value of i to 1 to offset the error.
By the way your code is written, I assume that you wish for your inner loop to run 10 times, not 11. This would explain why you are getting an extra iteration, and the issue is quite unrelated to the use of number_format. If you are only getting 10 iterations when you don't use that function, you might want to make sure that the statement 1 == 1 evaluates to true in your PHP interpreter.
Additionally, as a code styling issue, I would recommend using consistent case in your statements; you write foreach (lowercase) but also use For (uppercase). The convention is to use lowercase for both.
I have no clue why you would be only getting 10 iterations without number_format. You might be counting incorrectly? Try changing it to < and see if that resolves your issue.
# Permission
7 read and write and execute (1+2+4)
6 read and write (2+4)
5 read and execute (1+4)
4 read only
3 write and execute (1+2)
2 write only
1 execute only
0 none
I like the pattern that you can store any combination of the options options in one integer number, and add options by doubling the last number (8, 16 ,32 etc).
I'd like to use this method, and I'd like to know if there's a name for it, and what is the fastest simplest method for turning numbers into results similar to this?
array(1=>false,2=>true,4=>true);//6
array(1=>true,2=>true,4=>true,8=>true);//15
Using bitwise operations as recommended. To get the array you are after.
This function will figure out the number of bit required for any value given and return the array in the format you suggested.
I've included a loop for 0 to 20 to verify.
<?php
function getBitArray($value) {
$numberOfBits = ceil(log($value + 1, 2));
$result = array();
$bit = 1;
for($i = 0; $i < $numberOfBits; $i++) {
$result[$bit] = ($value & $bit) == $bit;
$bit <<= 1;
}
return $result;
}
for($i = 0; $i < 20; $i++)
var_dump(getBitArray($i));
That's generally referred to as a bit field, and you can work with it using bitwise operators.
This method is known as bitwise operation, and is used in php like this. Here is a nice tutorial.
I'm attempting to solve Project Euler in PHP and running into a problem with my for loop conditions inside the while loop. Could someone point me towards the right direction? Am I on the right track here?
The problem, btw, is to find the sums of all prime numbers below 2,000,000
Other note: The problem I'm encountering is that it seems to be a memory hog and besides implementing the sieve, I'm not sure how else to approach this. So, I'm wondering if I did something wrong in the implementation.
<?php
// The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
// Additional information:
// Sum below 100: 1060
// 1000: 76127
// (for testing)
// Find the sum of all the primes below 2,000,000.
// First, let's set n = 2 mill or the number we wish to find
// the primes under.
$n = 2000000;
// Then, let's set p = 2, the first prime number.
$p = 2;
// Now, let's create a list of all numbers from p to n.
$list = range($p, $n);
// Now the loop for Sieve of Eratosthenes.
// Also, let $i = 0 for a counter.
$i = 0;
while($p*$p < $n)
{
// Strike off all multiples of p less than or equal to n
for($k=0; $k < $n; $k++)
{
if($list[$k] % $p == 0)
{
unset($list[$k]);
}
}
// Re-initialize array
sort ($list);
// Find first number on list after p. Let that equal p.
$i = $i + 1;
$p = $list[$i];
}
echo array_sum($list);
?>
You can make a major optimization to your middle loop.
for($k=0; $k < $n; $k++)
{
if($list[$k] % $p == 0)
{
unset($list[$k]);
}
}
By beginning with 2*p and incrementing by $p instead of by 1. This eliminates the need for divisibility check as well as reducing the total iterations.
for($k=2*$p; $k < $n; $k += $p)
{
if (isset($list[k])) unset($list[$k]); //thanks matchu!
}
The suggestion above to check only odds to begin with (other than 2) is a good idea as well, although since the inner loop never gets off the ground for those cases I don't think its that critical. I also can't help but thinking the unsets are inefficient, tho I'm not 100% sure about that.
Here's my solution, using a 'boolean' array for the primes rather than actually removing the elements. I like using map,filters,reduce and stuff, but i figured id stick close to what you've done and this might be more efficient (although longer) anyway.
$top = 20000000;
$plist = array_fill(2,$top,1);
for ($a = 2 ; $a <= sqrt($top)+1; $a++)
{
if ($plist[$a] == 1)
for ($b = ($a+$a) ; $b <= $top; $b+=$a)
{
$plist[$b] = 0;
}
}
$sum = 0;
foreach ($plist as $k=>$v)
{
$sum += $k*$v;
}
echo $sum;
When I did this for project euler i used python, as I did for most. but someone who used PHP along the same lines as the one I did claimed it ran it 7 seconds (page 2's SekaiAi, for those who can look). I don't really care for his form (putting the body of a for loop into its increment clause!), or the use of globals and the function he has, but the main points are all there. My convenient means of testing PHP runs thru a server on a VMWareFusion local machine so its well slower, can't really comment from experience.
I've got the code to the point where it runs, and passes on small examples (17, for instance). However, it's been 8 or so minutes, and it's still running on my machine. I suspect that this algorithm, though simple, may not be the most effective, since it has to run through a lot of numbers a lot of times. (2 million tests on your first run, 1 million on your next, and they start removing less and less at a time as you go.) It also uses a lot of memory since you're, ya know, storing a list of millions of integers.
Regardless, here's my final copy of your code, with a list of the changes I made and why. I'm not sure that it works for 2,000,000 yet, but we'll see.
EDIT: It hit the right answer! Yay!
Set memory_limit to -1 to allow PHP to take as much memory as it wants for this very special case (very, very bad idea in production scripts!)
In PHP, use % instead of mod
The inner and outer loops can't use the same variable; PHP considers them to have the same scope. Use, maybe, $j for the inner loop.
To avoid having the prime strike itself off in the inner loop, start $j at $i + 1
On the unset, you used $arr instead of $list ;)
You missed a $ on the unset, so PHP interprets $list[j] as $list['j']. Just a typo.
I think that's all I did. I ran it with some progress output, and the highest prime it's reached by now is 599, so I'll let you know how it goes :)
My strategy in Ruby on this problem was just to check if every number under n was prime, looping through 2 and floor(sqrt(n)). It's also probably not an optimal solution, and takes a while to execute, but only about a minute or two. That could be the algorithm, or that could just be Ruby being better at this sort of job than PHP :/
Final code:
<?php
ini_set('memory_limit', -1);
// The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.
// Additional information:
// Sum below 100: 1060
// 1000: 76127
// (for testing)
// Find the sum of all the primes below 2,000,000.
// First, let's set n = 2 mill or the number we wish to find
// the primes under.
$n = 2000000;
// Then, let's set p = 2, the first prime number.
$p = 2;
// Now, let's create a list of all numbers from p to n.
$list = range($p, $n);
// Now the loop for Sieve of Eratosthenes.
// Also, let $i = 0 for a counter.
$i = 0;
while($p*$p < $n)
{
// Strike off all multiples of p less than or equal to n
for($j=$i+1; $j < $n; $j++)
{
if($list[$j] % $p == 0)
{
unset($list[$j]);
}
}
// Re-initialize array
sort ($list);
// Find first number on list after p. Let that equal p.
$i = $i + 1;
$p = $list[$i];
echo "$i: $p\n";
}
echo array_sum($list);
?>
It's a pretty simple question, I always have to go check here and then I hit my head and say it's so obvious. But really after a week of not using it I usually end up writing
for ($i = 1; $i++; $i <= 10;) {
echo $i;
}
some Mnemonic might help
ICE:
Initialisation
Check
Execute
Think logical! The order is the same as the expressions are evaluated.
for ($i = 0; $i < 10; ++$i) {
echo $i;
}
// is same as
$i = 0; // 1.
while ($i < 10) { //2.
echo $i;
++$i; // 3.
}
They go in order.
for (expr1; expr2; expr3)
expr1: Evaluated once at the beginning of the loop
expr2: Evaluated at the beginning of each iteration of the loop
expr3: Evaluated at the end of each iteration of the loop
You want to initialize first, check the condition second, and increment (or decrement) your counter last.
START -> CHECK FOR DANGER -> MOVE AHEAD
for( $i = 0 ; $i < 100 ; $i++ )
Hope it helps :-)
Best of luck!
F
irst (initialisation)
O
Only while (condition)
R
Rolling on (incrementing or decrementing)
I may be daft but don't you want this structure:
for ( $i = 1; $i <= 10; $i++ )
{
echo $i;
}
I don't know of a Mnemonic to remember this structure I've always just seen it as:
STARTING OFF; DO WHILE THIS; PERFORM AFTER EACH ROTATION
Rather:
DEFINE PRIOR TO EXECUTION; DEFINE EXECUTION LIMITS; DEFINE OPERATION FOR EACH ROTATION
Just remember that the guard is always checked before the increment, so you write it before.
If you don't remember the guard is checked before the increment, you're in bigger trouble, because you don't know what the loop will do :p
SAM
Start your engine
Are we there yet?
Move