0

Does the code

int value = 5;

if(value==5)
    System.out.println("value is 5");
if(value==6)
    System.out.println("value is 6");

actually compute faster than

int value = 5;

if(value==5)
    System.out.println("value is 5");
else if(value==6)
    System.out.println("value is 6");

?

I would assume that it is faster, based on its name and all, but is that actually how it works? When translated to machine code, does it run faster?

If I had thousands of lines of code, would a program using "else if" run faster than one using only "if" statements? If so, by how much?

PS: I'm using Java but I think this applies to all languages

Edited by kedxu

7
Contributors
14
Replies
17
Views
4 Years
Discussion Span
Last Post by deceptikon
Featured Replies
  • 2

    The advantage of the second version (using `else if`) is that the condition is part of the *same construct*. That means if some condition within the `if/else if` tree equates to true then the processing of that tree stops and the code continues after the whole tree. In the case … Read More

  • Let me demonstrate why all your trivial examples and tests are flawed due to their simplicity. I created the following C example code: int just_if(int value) { int result = 0; if(value == 1) result = 2; if(value == 2) result = 4; return result * result; }; int else_if(int … Read More

2

The advantage of the second version (using else if) is that the condition is part of the same construct. That means if some condition within the if/else if tree equates to true then the processing of that tree stops and the code continues after the whole tree. In the case without an else if you are forced to evaluate each condition regardless of what happens before it.
Now, in some cases, that is what you want - you expect that every single condition is checked in line. Other times (like your example) you want to 'short-circuit' the processing as soon as any condition is true.

0

I think it's more a matter of the logic of your program. In the simple example you gave it probably wouldn't matter. Consider this though:

if x=1 then
    x=y
else if x>0 then
        x<>y
    else if x>0 then
            x=y*-1
        endif
    endif
endif



If x=1 then
    x=y
endif

If x>0 and x<>1 then
    x<>y
endif
if x<0 then
    x=y*-1
endif

See how you need extra programming to cover the situation to exclude x if x=1 from the second if statement. This is of course a very simple example as the logic gets more complicated using the else if statement can also help keep things simpler. Because everything inside the main if statment is related not just separate statements. As far as speed is concerned. Probably the only real test is running both sets of code and seeing if there is a significant difference in speed.

0

I think I wasn't clear in my question.

I was not asking about the logical function of else if.

I was asking whether or not it actually cuts down calculation time. Supposedly, calculation will skip over the entire "else if" segment of the code. For example, in my code:

int value = 5;

if(value==5)
    System.out.println("value is 5");
//these two lines would be ignored if value is 5...
else if(value==6)
    System.out.println("value is 6");

But does that necessarily mean the second code would run faster than the first code?

And tinstaafl I will try that suggestion and see what happens.

Edited by kedxu

0

Okay so here is the test I conducted, tell me if there's something wrong

Code 1:

public class justIf {


    public static void main(String[] args)
    {
        int val = 5;
        long temp;

        temp = System.currentTimeMillis();
        for(int i=0; i<100000; i++)
        {for(int j=0; j<100000; j++){for(int k=0; k<100; k++){
            if(val==5)
            {
                //do nothing
            }
            if(val==6)
            {
                //do nothing
            }
            if(val==7)
            {
                //do nothing
            }
            if(val==8)
            {
                //do nothing
            }
        }}}
        System.out.println((System.currentTimeMillis()-temp));
    }
}

Code 2:

public class elseIf {


    public static void main(String[] args)
    {
        int val = 5;
        long temp;

        temp = System.currentTimeMillis();
        for(int i=0; i<100000; i++)
        {for(int j=0; j<100000; j++){for(int k=0; k<100; k++){
            if(val==5)
            {
                //do nothing
            }
            else if(val==6)
            {
                //do nothing
            }
            else if(val==7)
            {
                //do nothing
            }
            else if(val==8)
            {
                //do nothing
            }
        }}}
        System.out.println((System.currentTimeMillis()-temp));
    }
}

I ran each code 5 times, waited three seconds before each run, and did nothing else in the meantime. These are the results:

Code 1 = (3550+3541+3554+3554+3553)/5 = 3548.4 milliseconds
Code 2 = (3549+3555+3577+3559+3555)/5 = 3559 milliseconds

That's only a difference of 10.6ms!? If it skips the "else if"s, shouldn't it take like 1/4th of the time?

0

The amount of time difference will depend on the complexity of your code. You can see there definitely is a time difference. Whether or not it is significant, will depend on how often the code segment is run and how complex the logic is. In a large involved program with a lot of decision making, as opposed to a lot of calculations, you will probably find a very significant time difference. In either case it's usually good practice to make your code as efficient as possible. It gets you ready for when it will really matter.

0

Actually I just realized that the "else if" program actually ran 10.6s slower than its if counterpart. I think my test needs more tuning, like maybe I should actually do something inside the ifs.

Edited by kedxu

0

For your tests, you may be experiencing branch prediction. You never change val and since all values are all constants in the conditionals it may even be the case that the compiler is capable of figuring out that the unused expressions can be removed. I'll run a seperate set of tests and post those results once complete.

0

Follow-up to my previous post. Here is the code:

#include <cstdio>
#include <algorithm>
#include <vector>
#include <sys/time.h>

unsigned long g_sum1 = 0;
unsigned long g_sum2 = 0;

void method1 (int val) {
    if (val == 0)   { g_sum1 += 1; }
    if (val <= 1)   { g_sum1 += 2; }
    if (val <= 2)   { g_sum1 += 3; }
    if (val <= 4)   { g_sum1 += 4; }
    if (val <= 8)   { g_sum1 += 5; }
    if (val <= 16)  { g_sum1 += 6; }
    if (val <= 32)  { g_sum1 += 7; }
    if (val <= 64)  { g_sum1 += 8; }
    if (val <= 128) { g_sum1 += 9; }
    if (val <= 256) { g_sum1 += 10; }
    if (val <= 512) { g_sum1 += 11; }
}

void method2 (int val) {
    if (val == 0)   { g_sum1 += 1; }
    else if (val <= 1)   { g_sum2 += 2; }
    else if (val <= 2)   { g_sum2 += 3; }
    else if (val <= 4)   { g_sum2 += 4; }
    else if (val <= 8)   { g_sum2 += 5; }
    else if (val <= 16)  { g_sum2 += 6; }
    else if (val <= 32)  { g_sum2 += 7; }
    else if (val <= 64)  { g_sum2 += 8; }
    else if (val <= 128) { g_sum2 += 9; }
    else if (val <= 256) { g_sum2 += 10; }
    else if (val <= 512) { g_sum2 += 11; }
}

int main () {
    std::vector< long > values;
    values.reserve (512);
    for (int i = 0; i < 512; ++i)
        values.push_back (i);
    std::random_shuffle (values.begin (), values.end ());
    for (int i = 0; i < 100000; ++i)
        for (int j = 0; j < 10000; ++j)
            method1 (values[(i*j)%512]);
    struct timeval start, end;
    gettimeofday (&start, NULL);
    for (int i = 0; i < 100000; ++i)
        for (int j = 0; j < 10000; ++j)
            method1 (values[(i*j)%512]);
    gettimeofday (&end, NULL);
    fprintf (stderr, "Method1 Start: %ld.%06ld\n", start.tv_sec, start.tv_usec);
    fprintf (stderr, "Method1   End: %ld.%06ld\n", end.tv_sec, end.tv_usec);
    gettimeofday (&start, NULL);
    for (int i = 0; i < 100000; ++i)
        for (int j = 0; j < 10000; ++j)
            method2 (values[(i*j)%512]);
    gettimeofday (&end, NULL);
    fprintf (stderr, "Method2 Start: %ld.%06ld\n", start.tv_sec, start.tv_usec);
    fprintf (stderr, "Method2   End: %ld.%06ld\n", end.tv_sec, end.tv_usec);
    return 0;
}

The results of that are not too different from yours:
27.53 seconds for method1
26.16 seconds for method2

Although, I haven't looked at what the compiler actually outputs for each of those functions.

0

@L7Sqr method1 and method2 do two different things. Consider method1(0) and method2(0). In method1 all if gets executed in method2 only the first if gets executed. So I want to make note of the logistic difference between multiple if versus elseif

0

@firstPerson: You are absolutely correct. A alternate approach would be to have non-overlapping conditional statements in method1.

Although, the fact that they overlap can be enlightening in that it is entirely possible to have input that will exercize all cases of method1 but you can only ever execute a single contitional body in method2.

2

Let me demonstrate why all your trivial examples and tests are flawed due to their simplicity. I created the following C example code:

int just_if(int value) {
  int result = 0;
  if(value == 1)
    result = 2;
  if(value == 2)
    result = 4;
  return result * result;
};

int else_if(int value) {
  int result = 0;
  if(value == 1)
    result = 2;
  else if(value == 2)
    result = 4;
  return result * result;
};

int main() {
  return just_if(1) + else_if(2);
};

which I then compiled to obtain the assembly listings for it. Here is how the "just_if" function looks like:

_Z7just_ifi:
.LFB0:
    cmpl    $1, %edi      // compare 'value' to 1
    movl    $4, %eax      // put value of 4 in 'result' (eax)
    je  .L2               // if comparison was true, jump to L2 (just returns)
    xorb    %al, %al      // set 'result' to zero (using bitwise-xor)
    movl    $16, %edx     // put value of 16 in edx
    cmpl    $2, %edi      // compare 'value' to 2
    cmove   %edx, %eax    // if comparison was true, set 'result' to edx (16)
.L2:
    rep
    ret                   // return

And here is the else_if function:

_Z7else_ifi:
.LFB1:
    cmpl    $1, %edi      // compare 'value' to 1
    je  .L9               // if comparison was true, jump to L9
    xorl    %eax, %eax    // set 'result' to zero (using bitwise-xor)
    movl    $16, %edx     // put value of 16 in edx
    cmpl    $2, %edi      // compare 'value' to 2
    cmove   %edx, %eax    // if comparison was true, set 'result' to edx (16)
    ret                   // return
.L9:
    movl    $4, %eax      // put value of 4 in 'result' (eax)
    ret                   // return

And so, you see, there is no difference at all, except for the trivial displacement of the movl $4, %eax instruction. So, technically, the else_if version saves one instruction, but that's just a random fluke as to how the compiler decided to optimize the code. I also tried with more conditions and a bit more complex conditions, and the situation is the same all the time. Btw, to demonstrate that compilers are indeed pretty smart, here is the code that it produced for the main() function:

main:
.LFB2:
    movl    $20, %eax     // set value of 20 to the result register
    ret                   // return

That's why you have to be pretty careful about making up small performance tests, because very often the compiler is so smart that it'll optimize away everything you are trying to test, and the differences that you do measure will be nothing more than flukes or natural variability in execution times.

So, the conclusion is that it most likely makes no difference at all for simple enough conditions because any compiler (or VM) should be smart enough to deal with these situations. Remember, we, as humans, look at the code differently than a compiler does. The compiler always has to break things down to their essential effects and then put that into binary / assembly / byte-code form, it doesn't care much whether you write if vs. else-if, as long as the code essentially does the same thing, it will produce the same code at the end (aside from a few case-specific flukes). For any non-trivial conditions (like calling a complex function at each if-statement), then the compiler won't be able to infer the mutual exclusion of the different cases and it will be forced to evaluate all the conditions if you didn't use the else-if pattern, and that's where you'll pay a price for not using else-if, but that's obvious, isn't it?

So, to be on the safe side, whenever there is mutual exclusion between the conditions, use an else-if statement, even for simple conditions (like integer comparisons), in case the compiler can't figure it out on its own.

0

@mike_2000_17

To be fair, your example (of main) is pretty much straightforward constant folding; I wouldn't expect to see much more than that in the ASM.

Also, I fully agree that none of the tests provided here are rigorous but they do answer the question for a particular case. In the simple case, no, there is no difference.

As an aside, I like how you begin your post: Let me demonstrate why all your trivial examples and tests are flawed... ;-)

0

Never use if statement again and again for a single task it comsume more time so now lets move to elseif it comsume less time then multiple if statement and finally there is one more tool exist in almost all programing language called switch case statement.

And i will suggest to use switch case statement for more fast functioning . .

Edited by rishif2

0

And i will suggest to use switch case statement for more fast functioning . .

Potential for "more fast functioning". Switch statements are generally implemented as a lookup table, but there are possible degenerate cases that can affect performance and the suitability of a switch over an if chain:

  1. If the cases are far apart, such as this:

    switch (foo) {
        case 0:   do_something();      break;
        case 100: do_something_else(); break;
    }
    

    Then the switch is far more likely to be generated internally as an if chain:

    if (foo == 0)
        do_something();
    else if (foo == 100)
        do_something_else();
    

    The reason is that generating a lookup table with a large number of unused indices is wasteful as well as potentially slower in terms of cache misses.

  2. A switch is unsuitable for range-based comparisons. If you need to do something like converting a numeric point value into letter grades, if chains are superior in terms of readability:

    if (grade >= 90)
        return 'A';
    else if (80 <= grade && grade <= 89)
        return 'B';
    else if (70 <= grade && grade <= 79)
        return 'C';
    else if (65 <= grade && grade <= 69)
        return 'D';
    else
        return 'F';
    
This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.