POW function behaving strangely

When trying to pass a int into a function and use POW function is returning a 7 instead of 8.

int FS::free_mem(int block) {

    int try_diff = 3;
    int pos = block/8;
    int power = block % 8;

    int temp;
    temp = pow(2,power);

    Serial << "pos: " << pos << endl;
    Serial << "power: " << power << endl;
    Serial << "temp: " << temp << endl;

    return 0;
}

If the param function value was 83, making power variable 3, When I print out “temp” in the above code it gives me 7. If I type 3 into the POW function I get 8 or if I set a variable (like “try_diff” above) to 3 I get 8.
This leads me to believe it has something to do with the variable being passed in.

function is being used like: fs.free_mem(83);

Not sure what is going on here any help would be awesome, thanks.

RetroCheck: Not sure what is going on here any help would be awesome, thanks.

I think it has something to do with finally assigning an (exact) integer value with the (accurate to 6-7 significant digits only) result of a floating point number calculation. WITHOUT ROUNDING.

If that way the result would be 7.999999 and you assign it to an int, you'd get 7.

There may be a discrepancy in the results, if the compiler (32-bit GCC on your PC) can evaluate your constant expression during compile time and if the AVR (8-bit Atmega) calculates the result during execution time.

When doing integer calculations, you'd perhaps better avoid the usage of floating point functions. Or maybe use rounding functions and round to the nearest int value.

temp = pow(2,power);

On a computer that works in binary, there’s never any reason to use a function ike this to get powers of 2.

Use this instead:

temp = 1 << power;

It’s way way way faster, uses less code, and won’t have any rounding issues.

Ah I see, thanks you guys. I appreciate it!

Also, when you use pow(), it expects both arguments to be double. Therefore, if you want to raise 2 to the 3rd power, don't use pow(2, 3). Instead, you should write it as:

temp = pow(2.0, 3.0);

Now it's clear to the compiler what your intent is.

No, this makes it clear:

temp = (int) pow((double) 2, (double) 3);

I expect that writing "2.0" creates a float, not a double. Although double is identical to float on most Arduinos.

It's the cast to (int) that red-flags the original problem. Floats are not exact and lopping the decimals off doesn't always do what you intended.

No, this makes it clear: Code: [Select] temp = (int) pow((double) 2, (double) 3);

For the Arduino compiler, the floating point constants I used result in a float because the compiler doesn't support double*s. I would argue that your casts using *double is misleading precisely because double*s aren't supported. The *int cast on the result is a good idea, since the compiler is performing a silent cast and yours makes the cast explicit.

POW returns a float/double BUT temp is an int and when converting to int from float/real/double the number is always rounded DOWN. In the case POW is returning 7.99... (print it out) and that gets rounded down to seven.

Mark

... temp is an int and when converting to int from float/real/double the number is always rounded DOWN.

Actually, there is no rounding. It simply truncates the value.