Why not use if within a cycle for

2

Hello, my question is this:

for (int i = 2; i < n; i++)
        if (n % i == 0)
            return false;

    return true;

Given an example like anybody like this where I have a if within a cycle for , the teacher told me:

1) A if should not go within a for because you are not understanding the essence of for and to compensate you put the if , what you should put is a while .

2) The essence of for is to repeat the number of times according to the condition given in your block and what you are doing is cutting the cycle with a return , (something that should not be done with a break )

So, why do many codes have a if within a for ?

    
asked by neoprox 24.01.2018 в 05:19
source

3 answers

6
  

An if must not go inside a for because you are not understanding the essence of the for and to compensate it you put the if, what you should put is a while.

An answer too generic to be true.

Perhaps for the example that shows the use of if is excessive, since you could get exactly the same without using additional control structures:

bool ok = true;
for( int i=2; i<n && ok; i++ )
  ok = ((n % i) == 0);
return ok;

But it is perfectly legal to use a if within a for (otherwise your code would not compile) and, as I said, sometimes it is recommended or even necessary ... How would you go through an array of numbers and do a different operation depending on whether the number is even or odd ?:

for( int i=0; i<n; i++ )
{
  if( coleccion[i] % 2 == 0 )
  {
    // operaciones para numeros pares
  }
  else
  {
    // operaciones para numeros impares
  }
}

What your teacher really means is that, as a general rule, it is not well seen that a function has several exit points since this makes it difficult to debug (If you check a bit the code you have put you will see that it has 2 return , that is, two different exit points). Of course, it is important to stress that of as a general rule as it is sometimes preferable to have several exit points for simple readability (but this is already a personal opinion).

So, I would prefer to have this:

if( !/* chequeo 1 */ )
  return;

// operaciones ...

if( !/* chequeo 2 */ )
  return;

// operaciones ...

if( !/* chequeo 3 */ )
  return;

// operaciones ...

To this:

if( /* chequeo 1 */ )
{
  // operaciones ...

  if( /* chequeo 2 */ )
  {
    // operaciones ...

    if( /* chequeo 3 */ )
    {
      // operaciones ...
    }
  }
}

Basically, because a code with an excessive number of indentations is complicated to read ... there comes a time when it is not easy to know which is the closing key of a block and making modifications can be a very delicate task. But as I said, this point is something personal and there will be programmers who do not share my point of view.

    
answered by 24.01.2018 / 07:46
source
5

There are two points, the question of the if and the question of the additional point of saliency the if , with aspects of performance and readability.

Performance

In any case, it seems related to the loop unrolling technique.

In short, a processor does not execute an instruction in only one phase, but in several. So, to improve the performance, it is "advancing work" and begins to work on the following instructions before finishing the ones already in progress 1 . In addition, there are other dependencies (an instruction needs data that calculates a previous instruction).

This causes problems with the jumps, because the processor does not know which instruction will be executed. One usually chooses to choose one of the possible options and, if it turns out that it is not fulfilled, "eliminate" the half-executed instructions 2 , but it supposes a loss of performance.

One of the options is to try to make predictions based on previous performance 3 , but there are auxiliary techniques and one of them is the loop unrolling .

This is based on "unroll" the loop and have each iteration programmed as several. For example

for(int i = 0; i < miArray.size; i++) {
   acumulado += miArray[i];
}

really just become:

for(int i = 0; i < (miArray.size /3) * 3; i = i+3) {
  acumulado += miArray[i];
  acumulado2 += miArray[i + 1];
  acumulado3 += miArray[i + 2];
}
acumulado += acumulado2 + acumulado3;

more additional code to deal with the latest array data.

This not only reduces the number of hops, but also gives the compiler more freedom to rearrange the instructions so that the data dependencies do not "lock" the pipeline .

Naturally, the more complicated the logic of the loops and the more possible exit points exist, the harder it is for the compiler to optimize the loop in this way. This meant that the for were traditionally more rigid than the while , in order to take advantage of this advantage; for example, you could not change the value of the condition within the block that was executed.

Actually, I can not tell you to what extent processors still need (and compilers using) ' loop unrolling and to what extent a code like yours is a problem for a modern compiler if it wants to do an optimization, but I would be surprised if it meant a significant difference.

Readability

If it is correct that the custom causes that, when you see a for , you expect that the execution does not depend on anything that is not what you define in for itself (and therefore, you expect it to iterate) on all the elements).

In your code it is not difficult to see the break , but in larger blocks it can be ignored.

TL / DR The problem with if looks like a remnant of past times; but I would advise that, if you are going to use break or exit "unexpectedly", use a while for readability.

1 This is called pipelining .

2 This is related to a recently discovered vulnerability.

3 Normally the jump of a loop will be executed many times, and only once will it not be executed.

    
answered by 24.01.2018 в 12:11
4

The problem is not that there is if s within a loop for , that's normal; the problem arises when that if is used to break the normal flow of the loop. It is a sign that perhaps the selected loop is not the correct structure and, although technically valid, it is code that does not finish smelling well ( code smell ).

It's not that you can not do it with a for and that you have to use while . The idea is that, although you can, each structure has a utility and functionality and should be used according to it . For example: you can use pliers to hit a nail and put it on the wall, but for that there are already hammers. Yes, it will work and the result will end up being the same ... but it is not the best way.

And in the case of the question, maybe a while like this:

while (i<n && n%i!=0) { 
    ... 
    i++;
}

It would be more natural because it makes the stopping conditions of the loop and its goal clearer, than a for with break / return inside ... although the subject of readability it's relative because what is easy for one to read may not be for another.

    
answered by 24.01.2018 в 09:37