funziona:
...
Why?
The second part is pretty easy to show. The avr-libc pow() function actually works in floating point arithmetic.
Print floating point results to see the effects of using floating point arithmetic.
void setup()
{
Serial.begin(9600);
}
void loop()
{
for (int i = 0; i < 3; i++) {
Serial.print("pow(2,");
Serial.print(i) ;
Serial.print("):") ;
Serial.println(pow(2,i),7) ;
}
delay(1000);
}
Output
[color=blue]
pow(2,0):1.0000000
pow(2,1):2.0000000
pow(2,2):3.9999995[/color]
Now, if you cast a floating point number to an integer, the fractional part is truncated, so the numbers printed out would be integers 1, 2, 3, as you see with the second sketch.
(This is a Very Big Deal.)
Now as for the first sketch: Here the smarty-pants optimizing compiler looks at your code very carefully: It sees that you are setting a variable to a constant value. You don't change the value before calling the pow() function, and the other argument is also a constant. The avr-gcc compiler, believe it or not, has a built-in pow() function (above and beyond the standard math library function) and the compiler can see that you are calling pow() with two constant integers. It even knows ways of calculating integer powers of integers (within a certain range) without using floating point arithmetic. It does the work for you at compile time and plugs the (exact) value 4 into the assembled code so that it doesn't even have to do any of the actual work at run time.
In my opinion, that's just phenomenal. My flabber is totally gasted.
Note that this sneaky, tricky stuff about the optimization is not any part of the standard C (or C++) language specification, and things might be handled differently with different compilers or different versions of the same compiler. Sometimes the degree of optimization can be controlled by command-line switches when the compiler is invoked. So you can't count on any particular compiler doing the constant integer power stuff exactly. (A little numerical pun here, get it? Can't count on it. No? Oh, well...) See Footnote.
Bottom line: The first sketch just happens to use integer arithmetic and gives exact values for the particular arguments that are used. The second sketch, using floating point arithmetic, is susceptible to floating point arithmetic errors, which just happen to show up the third time through the loop, but not for the first two times.
Regards,
Dave
Footnote:
When dealing with floating point arithmetic, you must always (yes always) be aware of the possibility of roundoff error.
In the second sketch, since the power is calculated several times in a loop with different arguments, the compiler does not (can not, without unrolling the loop) calculate the result at compile time. The code calls the standard math library function pow() to do the calculation at run time.
There is only one pow() function in the avr-libc library, and it has floating point arguments, so the compiler "promotes" the arguments in the sketch to floating point values and works on them with floating point arithmetic.
In the avr-libc library, the pow() function calculates "x = a to the power b" by a floating point calculation equivalent to the following mathematical definition:
x = exp(b*log(a))
Where exp() is the exponential function and log() is logarithm to the base e.
The function is implemented in assembly language in the file pow.S in the libm/fplib directory of avr-libc source tree. Roundoff error is always a possibility. But I said that already.