Should calculations be repeated in if statements? - php

If a calculation is used in the evaluation expression of an if statement and then again in the execution statement(s), is it more or less efficient to perform the calculation twice or to introduce a new variable?
In other words, is
if ($x <> some_complex_calculation()) {
...
$x = some_complex_calculation();
}
better than this:
$result = some_complex_calculation();
if ($x <> $result) {
...
$x = $result;
}
Or, is this:
if ($x <> get_something_from_database()) {
...
$x = get_something_from_database();
}
better than this:
$result = get_something_from_database();
if ($x <> $result) {
...
$x = $result;
}

Of course it will always be more efficient to save the results of the calculation, no matter how trivial it may be, so if that is all you care about using a temporary is the only "correct" option.
That said, the performance aspect would only be important if the calculation takes up a sizeable amount of your total running time, which is unusual in practice. On the other hand, there are other considerations that can influence or even dictate your decision:
Correctness: If you do the calculation twice there is the possibility that the application state will have changed between the two calculations. So you would enter a branch because e.g. get_something() > 5 but then inside the branch it could be that get_something() <= 5 because someone else has modified the data in the meantime. Does it matter to you? How do you want the app to behave in this case? These are questions far more important than "is it going to run faster".
Understandability: Whenever I see a variable being defined, I usually have to allocate a "mental slot" to tracking that variable and its usages until I have figured out how the function it is defined in works as a whole. If the code is using too many temporaries then the cognitive load to the reader is increased. Does it matter to you? What is the relative impact vs the performance difference?

If the calculation has different arguments at each call and thus different results, then you will need to call it each time. For example:
function add( a, b )
{
return a + b;
}
And called like so:
if( add( 1, 2) > a )
else if ( add( 4,5 ) > c )
This would return different values each time so you would need to compute it in the if.
However if it is the same comparison value each time, it better to store the result if used more than once:
result = add(5, 6)
if( result > 10 )
else if( result > 12 )

Related

Most efficient of using 'if' [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Code 1 :
if( !(varOfsomeClass->isValid($imParams)) ){
//some function i need to run
}
run function isValid
reverse value with not (!)
check value with if
Code 2 :
if( (varOfsomeClass->isValid($imParams)) ){
} else {
//some function i need to run
}
run function isValid
check value with if
enter else part(maybe, or do nothing because isValid is true)
which is more efficient? which is better to use?
nb: Code 1 is indeed more 'human'
if( !(varOfsomeClass->isValid($imParams)) ){
//some function i need to run
}
This type code use Less resource when comparing with code 2 type.
Well, I would say example #1 is more efficient, but I doubt this type of micro-optimization will give you performance gains even measurable in micro seconds, so it's not worth it.
Remember, the if() itself evaluates the expression passed to it for truthly/false values, so adding ! is only redundant in most cases.
In other words, why would you need to do:
$number = 1;
if(!$number){}
instead of this.
$number = 1;
if($number){}
unless you are trying to quickly output something if $number is false, then move on to something else, it does not make any sense to use the first one.
It looks like you are not doing anything in the case isValid returns true. I would recommend to stick with the first version, where you only have a single if statement, for multiple reasons:
Less code to read, easier to understand
Leaving an empty block can be interpreted as "code not finished" for other contributors
Technically speaking, except a JUMP assembly instruction saved maybe (depending on the interpreter), both code will be as efficient... Do not try to think about those micro-optimization if it makes the code less readable.
An interesting question.
I would suggest to put it in this mini test suite and test it out:
$startA = microtime(true);
for($i = 0; $i < 10000; $i++)
{
//Code 1
}
$endA = microtime(true);
unset ($all, $your, $variables);
$startB = microtime(true);
for($i = 0; $i < 10000; $i++)
{
//Code 2
}
$endB = microtime(true);
echo $endA-$startA."<br />";
echo $endB-$startB."<br />";
They are both equaly effective.
The first on needs an additional ! negate statement, the second on has an additional else statement. The C code php uses is very effective when handling if/else constructs. It might even be the case that the second statement will get reduced to something similar like the first function in the ast parser.
However the second one is less readable an I would prefere the first one.
The best using if is depend on how you need your return value,
If you need return value not condition (reverse / false) only, u could use :
if ( ! varOfsomeClass->isValid( $imParams ) ){
//some function you need to run
}
If you need the right (true) return value, then use :
if ( varOfsomeClass->isValid( $imParams ) ){
// some function you need to run true
}
If you need true and false (both) return value, then use :
if ( varOfsomeClass->isValid( $imParams ) ){
// some function you need to run true
} else {
// some function you need to run false
}
And for your note, don't ever use this :
if ( varOfsomeClass->isValid( $imParams ) ){
} else {
//some function you need to run
}
That's what you called not 'human', it's like you are light but u are doing dark. :)

PHP variable declarations or function "recall"

I got really basic question about variables and function calls. I don't know how to name this question, so couldn't find any answer using search...
So is there somekind performance difference between these two codes:
Example 1:
if($Page->getCurrentPage('id') == 1) {
foreach($Page->getPagePosts() as $key => $pagePost) {
include(PATH_TEMPLATES. "post.php");
if(count($Page->getPagePosts()) - 1 > $key) {
echo "<hr>";
}
}
}
Example 2:
$arr = $Page->getPagePosts();
if($Page->getCurrentPage('id') == 1) {
foreach($arr as $key => $pagePost) {
include(PATH_TEMPLATES. "post.php");
if(count($arr) - 1 > $key) {
echo "<hr>";
}
}
}
Previously I have used Example 2, but not I started thinking if Example 1 is correct too.
It depends on your application and scale. Basically it is strongly recommended to ignore trivial performance optimization for the sake of better readability, scalability and maintainability. But there might be instances where you are going to iterate for 1000 times, which then, come costly if you ignore certain standards.
About your first example, in small cases it is OK, but in large calculations, it is best to avoid function-call in any type of loop, and it is best to pass an array to them as there would be no function overhead.
Therefore,
foreach( $users as $user)
{
//....
}
is better than
foreach( $this->getUsers() as $user)
{
// ....
}
But there are cases where you can simply ignore such seriousness, for example, in case your site only have two different logos, or at most, 5-records in a table, you can still stick to function-call in the loops:
foreach( $this->siteLogos() as $logo )
{
// ....
}
While I always read that using count() in for-loop must be avoided.
Online benchmarks say that foreach is faster than for-loops, which I'm not sure and invite you to have a research on it.

Create a Counter within a For-Loop?

I am a novice programmer and apologize upfront for the complicated question.
I am trying to create a lexical decision task for experimental research, in which respondents must decide if a series of letters presented on the screen make a "word" or "not a word". Everything works reasonably well except for the bit where I want to randomly select a word (category A) or nonword (category B) for each of 80 trials from a separate input file (input.txt). The randomization works, but some elements from each list (category A or B) are skipped because I have used "round.catIndex = j;" where "j" is a loop for each successive trial. Because some trials randomly select from Category A and other from Category B, "j" does not move successively down the list for each category. Instead, elements from the Category A list may be selected from something like 1, 2, 5, 8, 9, 10, and so on (it varies each time because of the randomization).
To make a long story short(!), how do I create a counter that will work within the for-loop for each trial, so that every word and nonword from Category A and B, respectively, will be used for the lexical decision task? Everything I have tried thus far does not work properly or breaks the javascript entirely.
Below is my code snippet and the full code is available at http://50.17.194.59/LDT/trunk/LDT.js. Also, the full lexical decision task can be accessed at http://50.17.194.59/LDT/trunk/LDT.php. Thanks!
function initRounds()
{
numlst = [];
for (var k = 0; k<numrounds; k++)
{
if (k % 2 == 0) numlst[k] = 0;
else numlst[k] = 1;
}
numlst.sort(function() {return 0.5 - Math.random()})
for (var j = 0; j<numrounds; j++)
{
var round = new LDTround();
if (numlst[j] == 0)
{
round.category = input.catA.datalabel;
}
else if (numlst[j] == 1)
{
round.category = input.catB.datalabel;
}
// pick a category & stimulus
if (round.category == input.catA.datalabel)
{
round.itemtype = input.catA.itemtype;
round.correct = 1;
round.catIndex = j;
}
else if (round.category == input.catB.datalabel)
{
round.itemtype = input.catB.itemtype;
round.correct = 2;
round.catIndex = j;
}
roundArray[i].push(round);
}
return roundArray;
}
You can use the comma operator to declare multiple variables and execute multiple statements within a single for loop.
In your case, you could do something like:
for(var CatAIndex = 0, CatBIndex = 0; CatAIndex+CatBIndex < numrounds; incrementA ? CatAIndex++ : CatBIndex++) {
// Insert your code here
}
I chose those verbose variable names to make it more clear. You'd have two separate indices for category A and B, and you compare the sum of the two versus the number of rounds you want to run. Then inside of your for loop somewhere, you set the boolean incrementA to either true or false to indicate which one to increment.
That roughly matches what you're asking for, but I think what you'd prefer is to use a combination of Math.random, <array>.splice and <array>.length to get a random word/nonword from each list, rather than producing a predictable order for selection. Then you don't even care what the indices are for the two categories and you can go back to a simple for(var i = 0; i < numrounds; i++) type of loop.
If the latter is what you really want, leave a comment on this answer and I'll update it with another example.
EDIT:
Okay, I'm assuming that the actual number and order of words and non-words is not really defined by your test, because otherwise a user could pick up the word/non-word pattern and Christmas Tree the test. I'm also assuming that you have two array of words and non-words called catA and catB in the global scope. Below is a function that will do the following:
Randomly pick a word or non-word.
Never repeat a word or non-word pick (meaning that technically it becomes more deterministic the closer to the end of the list you are.
Until all words are exhausted, at which point it will automatically "refresh" its list from the catA and catB arrays. (So you can set numrounds to +inf if you like.)
.
var pickAWord = (function outerScope() {
var allWords = [];
return function innerClosure() {
if(allWords.length == 0) {
allWords = [].concat(catA, catB);
}
return allWords.splice(Math.floor(Math.random()*allWords.length), 1)[0];
};
})();
The function is using the functional programming concept of closures to create a persisted "global-like" variable, allWords that only it can see. The function automatically refreshes the array with all of the words when the length of the array reaches zero (like it is from the start) using the globals catA and catB. To use it in a for loop, simply:
for(var i = 0; i < numrounds; i++) {
var wordToUse = pickAWord();
// Do something
}
If you need to guarantee that an equal number of catA and catB words are used, the outerScope function will need to keep track of three variables: copies of catA and catB, and an array the same size as numrounds, half of which are true and half false. splice randomly from this true/false array, and then splice randomly from either catA or catB depending on whether it's true or false. Then you function will need code to "refresh" all of these closure variables, but it would be essentially the same as how the function is written above.
Sorry if the function is a bit complex, but you see how easy it is to use, right? :)
I'm not entirely sure I understand your problem. Here is my answer based on this possible interpretations of your question:
You would like to use a for loop to process all of the Category A elements (and similarly another loop to process all Category B elements). In this case you can loop through the roundArray and treat the elements according to their category:
for (var j=0; j < numrounds, j++) {
var round = roundArray[i][j];
// you might want to use a test better suiting the context if input is not available at the
// time when round is processed, I am using this based on the code sample you provided
if (round.itemType == input.catA.itemType) {
// process round as Category A
// use numlst[round.catIndex] to access the corresponding element in numlst
} else {
// process round as Category B
// use numlst[round.catIndex] to access the corresponding element in numlst
}
}
// alternatively, you can break the loop into two and process only Category A in one instance
// and only Category B in the other (the if branch corresponding to the other category would be
// empty)
If this is not your intention, please clarify.

PHP how to reuse a function from a clean state

`I have a function called lets say calculate; what i want to do is run some loops with in the function calculating an outcome. at times this function does fail as it will get stuck in a loop, so iv got it covered to exit the loop but my problem is i want to restart this function and hope it come out with an outcome if not i will try again... on average the request does not have an outcome around 1 in 20, i need to restart the function from a clean slate.
i have tried to unset all the vars before i rerun the process with out success.please note this function will fail at times from the information handed to the process, un avoidable so
when this accurs i just want to rerun the function automatically to generate an outcome.
http://www.gamezslave.com/test/DynamicSlots.swf this is my test prototype give you an idea
sometimes you refresh it will error because of this factor.
<?php
$checker = 0; // if i cant get a result i could use this will tick up until condition
function shuffleArray($myArray) {
$value_count = array_count_values($myArray);
$last_value = $myArray[count($myArray) - 1];
unset($myArray[count($myArray) - 1]);
$shuffle = array();
$last = false;
while (count($myArray) > 0) {
$keys = array_keys($myArray);
$i = round(rand(0, count($keys) - 1));
while ($last === $myArray[$keys[$i]] ) {
$i = round(rand(0, count($keys) - 1));
echo "stuck";
$checker++;
if($checker>10){
echo " Too many checks so die, and restart process ";
return false;
bob; // this is the check function to goto and restart
}
}
$shuffle[] = $myArray[$keys[$i]];
$last = $myArray[$keys[$i]];
unset($myArray[$keys[$i]]);
}
if ($last_value === $last) {
$i = 0;
foreach($shuffle as $key=>$value) {
if ($value !== $last_value) {
$i = $key;
break;
}
}
array_slice($shuffle, $i + 1, 0, $last_value);
} else {
$shuffle[] = $last_value;
}
return $shuffle;
}
print_r(shuffleArray(array(1,5,5,3,7,7,7,7))); // just a example
function bob(){
if($checker>10){
$checker = 0;
shuffleArray();
echo "bob";
reset($myArray); // thought this may clean/reset the array i couldnt use
}
}
The idea this shuffle returns that no two symbols elemts of the same will be next to each other but sometimes at the end of the array as its shuffling randomly im left with bad odds (apple, orange, orange, orange) so what i need to do is resart this process again from start take in mind there is about 10 different item in the array and duplicates of each for example 10 apples ,10 oranges 4 bannanas 3 grapes sometimes the shuffle manages to generate an outcome where im stuck with too many of the same item at the end of the array wich then i need to rerun the script(and this bit is the problem) i dont know how.
Are you using globals?
If yes: Stop that. It's terrible practice. Seriously. There's never a reason to use globals with any sort of sane code.
If no: There's nothing to do. Each function invocation is a clean slate.
EDIT After seeing the code, I'm kinda speechless.
http://us3.php.net/manual/en/function.shuffle.php
I would set defaults to all variables inside of your function, and pass anything active as a parameter. Then use a set of return codes to indicate success or failure, or validate the outcome in some way and re-run.
I'm agreeing with Tyler Eaves here and i wanted to add as another reply a very important topic in programming:
A function "should" in theory be as scalar as possible meaning that it should not affect the outside world and should return the same information everytime for the same parameters.
If you call a function with parameter X, Y and Z and call it again while your system is in the same state, the function should return the exact same result.
But if a function is not scalar (Virtual for instance), such as dependant on external data (files, database rows or single instance accessible class data) then you should theorically not affect that external data from this function or else calling the function multiple times yield different results...

Is this the way to do this simple IF OR OR statement?

I have an if statement with a few or's in it.
i.e.
if($count == 1 || $count == 3 || $count == 7) {
// do stuff
}
I'm just curious - is this the best way to do this? With this simple example above, is there a faster way to do this, and if so, what is it?
Your code works fine. Alternately, you can use in_array(), which is a bit cleaner and scales better:
if (in_array($count, array(1,3,7))) { ... }
The code you've written is fine. As Paul Schreiber says, there are various other options that are a little neater.
One thing you may want to think about (and I know this is just an example) is why the values you're checking are important. Do they all have some property in common that you're checking? If so, then stating the property symbolically may make the code easier for someone to understand. For example:
if (is_odd($x) && $x < 10) {
//...
}
rather than
if ($x == 1 || $x == 3 || $x == 5 || $x == 7 || $x == 9 ) {
//...
}
This is quite a contrived example, but hopefully you see what I'm getting at.
As a more concrete example, instead of doing something like:
if ($user->age > 65
|| $user->years_of_custom > 3
|| $num_items > 5 ) {
// Give this user a discount ....
}
you might want to do:
if (eligible_for_discount($user, $num_items) ) {
// Give this user a discount
}
Even if you only use the function in this one place, this could increase the readability of the code. Obviously you have to use your judgment though, because you're increasing readability at the expense of having more lines of code to maintain, and that isn't always the right choice. If the conditions have little to do with each other, binding them up into a separate function might make no sense and make your code harder to follow, not easier. Focus on what your code actually means, and how a human being should understand it.
You can assign all possible value in an array and check using array_search function
$array=array(1,3,7);
if (array_search($count,$array) !== FALSE)
{
//do stuff
}
Wouldn't the switch statement be better?
switch ($count) {
case 1:
case 3:
case 7:
echo "do stuff";
break;
}

Categories