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?

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.

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.