Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If vs Continue statement in a for loop

I have a for loop in Matlab, and all the code inside the for loop is enclosed in an if statement. For example :

for p = 1:length(array)
    if array(p) == 1 %// Test positive for condition    
        %// Generic code here that
        %// Only executes if p == 1 
    end;                  
end; 

Is it faster to have test for equality using an if statement, and execute the interior code if true, or, to test for inequality and then use a continue statement, such as :

for p = 1:length(array)
    if array(p) ~= 1 %// Test negative for condition
        continue;   %// Skip if negative
    end;   
    %// Generic code here that
    %// Only executes if p == 1
end; 

Or, does it make no difference either way i.e. its optimized to the same result on execution?

As its only a micro-optimization its not terribly important - but I'm curious to know!

EDIT: Interestingly, after profiling the code as recommended, the latter seems to be fractionally faster - if anybody would care to explain that would be great! (After all, at best its the same logic but with extra instructions to be executed)

like image 674
davidhood2 Avatar asked Apr 17 '16 13:04

davidhood2


People also ask

Can you use continue in a for loop?

The continue keyword can be used in any of the loop control structures. It causes the loop to immediately jump to the next iteration of the loop. In a for loop, the continue keyword causes control to immediately jump to the update statement.

What is the effect of writing a Continue statement inside a loop?

Continue statement is often used inside in programming languages inside loops control structures. Inside the loop, when a continue statement is encountered the control directly jumps to the beginning of the loop for the next iteration instead of executing the statements of the current iteration.

Can you use continue in a IF statement?

You can't use continue with if (not even a labelled one) because if isn't an iteration statement; from the spec. It is a Syntax Error if this ContinueStatement is not nested, directly or indirectly (but not crossing function boundaries), within an IterationStatement.

Can you use continue and break in for loops?

The break and continue statements are the jump statements that are used to skip some statements inside the loop or terminate the loop immediately without checking the test expression. These statements can be used inside any loops such as for, while, do-while loop.


1 Answers

In theory, there should not be a performance difference between the two methods that you have proposed because the if statement has to be evaluated every time through the loop regardless, but let's take a closer look with some profiling (timeit). I have some tests below on versions R2014a through R2015b.

For each of these tests, I create an array p of varying sizes of an equal number of 1's and 0's and randomized the order of 0's and 1's.

%// Creates random zeros and ones of size n
p = mod(randperm(n),2);

For the first test, I disabled the JIT compiler feature('JIT', 'off') and the second test I enabled the JIT compiler feature('JIT', 'on').

The script I used for all versions of MATLAB was:

function tests()
    V = ver;

    sz = round(linspace(100, 10000,100));

    hfig = figure('Position', [0 0 900 400]);

    %// Disable JIT
    feature('JIT', 'off')
    runtests(sz, 1, ['JIT Disabled ', V(1).Release]);

    %// Enable JIT
    feature('JIT', 'on')
    runtests(sz, 2, ['JIT Enabled ', V(1).Release]);

    %// Match up ylims on all plots
    ax = findall(hfig, 'type', 'axes');
    ylims = get(ax, 'ylim');
    ylims = cat(1, ylims{:});
    set(ax, 'ylim', [0, max(ylims(:,2))])
end

function out = runtests(sz, n, label)

    times1 = zeros(numel(sz), 1);
    times2 = zeros(numel(sz), 1);

    for k = 1:numel(sz)
        p = mod(randperm(sz(k)),2);
        times1(k) = timeit(@()continueit(p));
        p = mod(randperm(sz(k)),2);
        times2(k) = timeit(@()ifit(p));
    end

    subplot(1,2,n)
    plots(sz, cat(2, times1, times2))
    title(label)
end

function plots(sz, times)
    plot(sz, times * 1000)
    legend({'Continue', 'If'})
    xlabel('Size of Array')
    ylabel('Execution Time (ms)')
end

function continueit(p)
    c = 1;
    for k = 1:numel(p)
        if p(k) ~= 1
            continue;
        end

        c = c * k;
    end
end

function ifit(p)
    c = 1;
    for k = 1:numel(p)
        if p(k) == 1
            c = c * k;
        end
    end
end

    
    

R2014a

As you can see here, continue and the if statement have very similar performance with no JIT acceleration turned on. However, when you turn on the acceleration (MATLAB's default), only the if statement seems to be accelerated. The speed of the continue approach remains relatively unchanged. As a result, the if statement would execute faster.

enter image description here

This is likely due to the fact that the JIT compiler accelerates blocks of instructions that are executed many times in a row. By sticking the branching logic with a continue in there, you are changing the flow of the program depending upon a condition and this changes the instructions that are run each time through the loop. This is apparently preventing JIT compilation.

R2014b

Similar to R2014a.

enter image description here

R2015a

Similar to R2014a.

enter image description here

R2015b (new execution engine introduced)

Unfortunately, in R2015b it doesn't seem that you can disable JIT in the same way (if anyone knows how, let me know and I'll update) so both of these plots have acceleration enabled, but it appears that the new execution engine removes the differences in execution time that the JIT compiler had previously created. This is because the new execution engine is able to JIT compile all code (including, obviously the continue)

From the MATLAB docs:

Just-in-Time Compilation of All MATLAB Code

The redesigned MATLAB execution engine uses JIT compilation of all MATLAB code, whereas the execution engine previously used JIT compilation in some cases. The JIT compilation generates native machine level code that is optimized for the MATLAB code being executed and for the specific hardware platform.

The performance benefit of JIT compilation is greatest when MATLAB code is executed additional times and can re-use the compiled code. This happens in common cases such as for-loops or when applications are run additional times in a MATLAB session with at least some of the application’s MATLAB files remaining unmodified between subsequent runs.

enter image description here

Summary

In older versions of MATLAB (R2015a and earlier), the continue statement prevented JIT acceleration causing the if version to execute faster when JIT was enabled (by default). With the introduction of the new execution engine in R2015b, all code is JIT accelerated and as such, the difference has effectively vanished.

As you noted though, the if statement is just barely faster still. This is likely due to the overhead of actually calling continue. This difference is negligible in the grand scheme of things. Furthermore, if the overall performance of your for loop really depends on this difference, it means that the speed of the contents of the loop is very fast and your bottleneck is the for loop itself and you should consider vectorizing your code (i.e. if I put a magic(3) call within my for loop instead of the simple multiplication shown here, the difference completely disappears).

like image 88
Suever Avatar answered Sep 29 '22 16:09

Suever