decrement vs. increment

I recently found this link in someones signature.(Sorry, I forget who)

Atmel AVR4027: Tips and Tricks to Optimize Your C Code for 8-bit AVR Microcontrollers

The example code is a little advanced for me, but it seems to be saying it's better
to count down than to count up in a loop.

so that

  for ( i = 10; i = 0; i--){}

is better than

for ( i = 0; i = 10; i++){}

since I never see anyone do it this way
I wondered if it applied.

Tip #3 – Loop index
Loops are widely used in 8-bit AVR code. There are “while ( ) { }” loop, “for ( )” loop
and “do { } while ( )” loop. If the -Os optimization option is enabled; the compiler will
optimize the loops automatically to have the same code size.
However we can still reduce the code size slight
ly. If we use a “do { } while ( )” loop,
an increment or a decrement loop index generates different code size. Usually we
write our loops counting from zero to the ma
ximum value (increment), but it is more
efficient to count the loop from the maximum value to zero (decrement).
That is because in an increment loop, a comparison instruction is needed to compare
the loop index with the maximum value in every loop to check if the loop index
reaches the maximum value.
When we use a decrement loop, this comparison is not needed any more because
the decremented result of the loop index w
ill set the Z (zero) flag in SREG if it
reaches zero.

To me it is more intuitive to use for ( i = 0;i=10;i++){}
IMO, the savings will surely not be noticeable.

I usually increment a for() loop but a while() loop can work nice with decrementing as it breaks at 0.

int n = 10;
while(n){--n;}

I think that's what that author was meaning. He was using a do{} while() loop.

For an eight bit index the difference is typically a single machine instruction. At the most it will be two. You will have to decide if that is an optimization worth pursuing.

Efficiency of decrementing has relation to test for zero value which can be little bit more efficient under some conditions than test for nonzero value.

The savings are on the order of microseconds. The reason for the saving is that checking to see if something is zero is very quick. To see if something is 10, the microprocessor has to subtract 10 and see if the result is zero. Microseconds.

A bit academic these days. The compiler figures out that you're looping N times, and produces identical code (using subtract) for both cases. (assuming you don't actually use the index...)

Never confuse "better" for "faster" - they are not the same. "Better" is meaningless
without qualification - more readable? less code space? faster execution? fewer bugs?

LarryD:
To me it is more intuitive to use for ( i = 0;i=10;i++){}

Not really. Maybe if you use:

i == 10
  for ( i = 10; i = 0; i--){}

That's wrong too.

for ( i = 10; i = 0; i--){} // WRONG!

for ( i = 10; i > 0; i--){} // counts from 10 down to 1

for ( i = 10; i >= 0; i--){} // counts from 10 down to 0

for ( i = 0; i = 10; i++){} // WRONG! This will never end!

for ( i = 0; i < 10; i++){} // counts from 0 up to 9

for ( i = 0; i <= 10; i++){} // counts from 0 up to 10

Thanks for the replies all. I just figured that if Atmel thought it important enough to include that it would be worthwhile.

odometer:

for ( i = 10; i = 0; i--){} // WRONG!

for ( i = 10; i > 0; i–){} // counts from 10 down to 1

for ( i = 10; i >= 0; i–){} // counts from 10 down to 0

for ( i = 0; i = 10; i++){} // WRONG! This will never end!

for ( i = 0; i < 10; i++){} // counts from 0 up to 9

for ( i = 0; i <= 10; i++){} // counts from 0 up to 10

I am printing this and putting it near my monitor.
It really demonstrates the importance of paying strict attention to syntax.

When I first came here I thought that some here were a little harsh on the newb’s.
But I am now starting to understand that coding is a unforgiving B****.

.

@Nick Gammon

To me it is more intuitive to use for ( i = 0;i=10;i++){}

:-[

To me it is more intuitive to use for ( i = 0;i<10;i++){}

Going to call you Hawkeye for keeping us/me on the straight and narrow.
.

for ( i = 10; i = 0; i--){} // WRONG!

You understand that there are two things wrong with this, right?

  1. The equality operator is "==", not "="
  2. the "condition" part of the for loop says when the loop continues, not when it stops.

I just figured that if Atmel thought it important enough to include that it would be worthwhile.

Meh.

  1. "premature optimization is the root of much evil" - in general, it's a bad idea to make your code faster at the expense of clarity, until you notice that you actually NEED the code to be faster.
  2. Compilers are better than they used to be; In general, you can trust a modern compiler to do reasonable things with "clear" code, so you don't have to obscure it.
  3. that is: "trust, but verify." If speed IS important, you need to look at the code that the compiler produces, not blindly try some trick you read about somewhere.
  4. different compilers are different. I mentioned that avr-gcc (used by arduino) creates identical code for up loops and down loops. That might not be true of other compilers.

Hutkikz:
I just figured that if Atmel thought it important enough to include that it would be worthwhile.

It is important. In extremely rare circumstances. In those rare circumstances it is worthwhile.

void setup()
{
  Serial.begin(9600);
  
  for (unsigned i=0; i<10; i++)
  {
    Serial.println(i);
  }

  for (unsigned i=10; i; i--)
  {
    Serial.println(i);
  }
}

void loop()
{
}

up test for 10

  e6:	21 96       	adiw	r28, 0x01	; 1
  e8:	ca 30       	cpi	r28, 0x0A	; 10
  ea:	d1 05       	cpc	r29, r1
  ec:	a9 f7       	brne	.-22     	; 0xd8 <setup+0x18>

down test for 0

 100:	21 97       	sbiw	r28, 0x01	; 1
 102:	b9 f7       	brne	.-18     	; 0xf2 <setup+0x32>

Yep, you've saved 2 cycles (125 nS). Whether that is worth the decreased readability of your code is up to you.

Optimizing code should only be done if the straightforward code does not meet requirements.

The two major optimizing requirements are speed and size (or both!).

SPEED:
2 cycles per iteration can become quite a lot if the amount of iterations become substantial, e.g. if you need to do timing for communicating with a sensor. Also if you want a fast interrupt routine.

SIZE:
When developing libraries, there is always the need to minimize the footprint to leave extra room for the user application. 4 bytes is not much but also here it adds up.

Jese Nick - sometimes you come across like a bear with a sore head. I posted this simply so the OP and anyone else that was interested could see what actually happens. I was making no comment whatsoever about what anyone should choose to use. Lighten up.