float & int math

Hi,

I read the relevant math tutorials, but I still don't understand what's going on here. This code is part of a music apparatus. I'm working with interval ratios that have to be expressed as floats.

Here I check each element in an array of floats called ratios against two other float arrays, upper & lower, which are +/- boundaries for possible interval types. Then the code assigns values to an integer array with integer powers of 2.

int * pointer = converted;
         for(int x = 0; x<(sizeof(ratios)/sizeof(float)); x++){
            for(int n = 1; n<12; n++){
              for(int l = 0; l<4; l++){
                if(ratios[x] <= (pow(2,l)*upper[n]) && ratios[x] >= (pow(2,l)*lower[n]))
                    {*pointer = (pow(2, n));v++;}}}}

For some reason, the integer values in converted are consistently 1 less than expected (e.g. 1, 3, 7, 15, etc.)

I know I can simply add 1 to the expression and move forward, but why is this happening?

Thanks!

Probably, you are seeing the results of pow() produce something like 1.999999, 3.99999, 7.99999, 15.9999 instead of 1.0, 2.0, 4.0 etc... then it is effectively floored (truncated to the lowest nearby integer) by the conversion to integer.

Can you see the danger of just adding 1?

Ah. Because pow() works with float datatypes. Thanks aarg. No, what's the danger of just adding one?

peterbradley:
Ah. Because pow() works with float datatypes. Thanks aarg. No, what's the danger of just adding one?

Some result of pow might come back as say, 64.0001. Thinking that you really got 63.9999, you add one and get 65!

To really fix this you need more than a band aid. You need to rethink the design.

You need to rethink the design.

Specifically, you need to quit using pow() with integer variables. pow(2, n) is FAR better expressed as 2 << n, which (with proper casting, if needed) will never have rounding issues.

+1
But you still might have errors in the comparison with floats in ratios[]. Not sure, but you better check:

if(ratios[x] <= (pow(2,l)*upper[n]) && ratios[x] >= (pow(2,l)*lower[n]))

You now need to examine the values that you put in ratios[] carefully.
Lowercase "l" is a bad variable name. It looks too much like "1" and "I".

PaulS:
expressed as 2 << n

You mean 1<<n

aarg:
You mean 1<<n

Well, they are right next to each other, and I've got fat fingers... But, yeah.

"[Floating-point] math is hard."

comparing floating point numbers

Huge improvement. Thanks!

A little late I know but could be done something like -

#define NUM_ENTRIES(ARRAY)      (sizeof(ARRAY) / sizeof(ARRAY[0]))


int*    pointer = converted;
for ( size_t x = 0; x < NUM_ENTRIES(ratios); x++)
{
    for ( size_t n = 1, power_outter = 1; n < 12; n++, power_outter <<= 1 )
    {
        for ( size_t l = 0, power_inner = 1; l < 4; l++, power_inner <<= 1 )
        {
            if ( ratios[x] <= (power_inner * upper[n]) && ratios[x] >= (power_inner * lower[n]) )
            {