16 to 32 bit floating point conversions

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

I'm in the process of writing a class to read in AIFF files into memory. While AIFF supports up to 32 bit floating point values, it's more common to see 16 and 24 bit values instead. My question is, how exactly do I go about reading the raw 16-bit values from disk and converting them internally to 32 bit floats? I've read the documentation on the IEEE 754 specs, but am still not clear as to how to actually make this conversion happen.... any ideas?

Post

Eh.. I probably don't get what you mean, but what's wrong with simply typecasting and scaling?

Post

Check out the wikipedia entry for floating point and you'll see what I mean.

Post

float val = (float)(int16_value) / 32768.0f;

Post

[ Ghetto answer removed cause stefancr's reply is much more elegant :) ]
Last edited by dblue on Wed Jun 07, 2006 4:34 pm, edited 2 times in total.
I'm Kieran, aka dblue, aka illformed | illformed.com | Glitch 2 now available for Windows, Mac and Linux!

Post

Thanks for the suggestions, guys. Let me try these out and see if I can't get things working. :)

Post

Ok, so nothing wrong with simply typecasting and scaling ;)

Post

BarendB wrote:Ok, so nothing wrong with simply typecasting and scaling ;)
Yeah, I guess not.... I think all the mantissa/exponent stuff freaked me out a bit. ;)

Post

sqook wrote:
BarendB wrote:Ok, so nothing wrong with simply typecasting and scaling ;)
Yeah, I guess not.... I think all the mantissa/exponent stuff freaked me out a bit. ;)
It is really not that bad. The only weird things about it are the bias in the exponent, and the fact that the mantissa is normalized. But if you practice with the formats just for a little while, it will be clear why these are good ideas.

As for converting from 32 bit to 16 bit, you must be willing to give up both precision and scale (of course). But you also have to decide whether you want your conversion to be direct and only consider those 32-bit floats that fit in the same scale as 16 bit floats (and overflow the rest), OR whether you want to map the 32-bit float range as a proportional scale, and approximate that scale in 16-bit.

Post

sqook wrote:Yeah, I guess not.... I think all the mantissa/exponent stuff freaked me out a bit. ;)
That's imaginable :) You can do some pretty useful stuff with that though, like fast absolute value by zeroing the sign bit:

Code: Select all

int iVal = (int&)fVal & 0x7FFFFFFF; 
fVal = (float&)iVal;
Or do a very fast float to 23bit int conversion by masking out the exponent bits (fVal must be limited to [0..1] range) for example:

Code: Select all

fVal += 1.f;
unsigned int iVal = (((unsigned int&)fVal) & 0x7FFFFF) << 9; // use 23bits mantissa
Last edited by BarendB on Wed Jun 07, 2006 6:06 pm, edited 3 times in total.

Post

Oops, my apologies, you want to up-scale 16 to 32 bit. I'm sure I'd still do it by padding the mantissa and re-scaling the exponent. It can be done with only logic and an add operation.
I'd try to avoid any floating point divide if at all possible.

Post

james0tucson wrote:Oops, my apologies, you want to up-scale 16 to 32 bit. I'm sure I'd still do it by padding the mantissa and re-scaling the exponent. It can be done with only logic and an add operation.
I'd try to avoid any floating point divide if at all possible.
Exactly what stefancrs said works, and with no divide, because, as the value that's divided by is a constant, it should optimize to...

float val = (float)(int16_value) * 0.000030517578125f;

...automatically, by the compiler. No?

(I don't actually know, cuz I always code them this way just to be sure. But I'd hope any complier would optimize divides by constants.)

Post

AdmiralQuality wrote:
james0tucson wrote:Oops, my apologies, you want to up-scale 16 to 32 bit. I'm sure I'd still do it by padding the mantissa and re-scaling the exponent. It can be done with only logic and an add operation.
I'd try to avoid any floating point divide if at all possible.
Exactly what stefancrs said works, and with no divide, because, as the value that's divided by is a constant, it should optimize to...

float val = (float)(int16_value) * 0.000030517578125f;

...automatically, by the compiler. No?

(I don't actually know, cuz I always code them this way just to be sure. But I'd hope any complier would optimize divides by constants.)
A floating point multiply is the same problem as a floating point divide.
I'm quite sure I would convert a 16-bit float to a 32-bit float as follows, that is if performance was an issue at all. (If it's not an optimization opportunity in the first place, then who cares??)

1. Set the sign bit of the new value
2. Set the mantissa by padding the 10 bit mantissa to the 23 bits of the target.
3. subtract the bias from the 5 bit exponent
4. AND the target with the normalized 8 bit value of the exponent

No multiply or divide involved.

If you want to scale the 32-bit values proportional to the 16-bit values, that's different. (I still think that can be done with only shifts, though.)

Post

james0tucson wrote: A floating point multiply is the same problem as a floating point divide.
I'm quite sure I would convert a 16-bit float to a 32-bit float as follows, that is if performance was an issue at all. (If it's not an optimization opportunity in the first place, then who cares??)

1. Set the sign bit of the new value
2. Set the mantissa by padding the 10 bit mantissa to the 23 bits of the target.
3. subtract the bias from the 5 bit exponent
4. AND the target with the normalized 8 bit value of the exponent

No multiply or divide involved.

If you want to scale the 32-bit values proportional to the 16-bit values, that's different. (I still think that can be done with only shifts, though.)
Could you write all that out in code though so I can actually see what you mean, and then tell me again it's more efficient than a cast and a mult? (And, if it was, wouldn't the cast do it your way too?)

And I assume you mean by proportional scale that we want the int range -32768..32767 to map to -1.0..1.0 in floats? What OTHER way would anyone EVER want to do this? How can you do this without a multiply somewhere?

If you did mash it up into an out of scale float, you're just going to have to scale it again (probably, depending on your application). But assuming you're reading wave data, you'd want 0 dB to come out as 0dB 99% of the time.

Sorry if I'm not getting something. Please show us in code to clarify? Maybe we can do a little test.

Post

AdmiralQuality wrote:And I assume you mean by proportional scale that we want the int range -32768..32767 to map to -1.0..1.0 in floats? What OTHER way would anyone EVER want to do this? How can you do this without a multiply somewhere?
Actually, that IS possible. This code will convert and scale an unsigned int sample value (iVal) in the range [0..32767] to a float in the range [0..1], without any multiplication:

Code: Select all

iVal = (iVal << 8) | 0x3F800000;
float fVal = (float&)iVal - 1.f;
The sign bit can be added to expand the range to [-1..1].
Last edited by BarendB on Thu Jun 08, 2006 1:02 pm, edited 1 time in total.

Post Reply

Return to “DSP and Plugin Development”