Suppose I have an API that only allows me to store floats, or arrays of floats. However, I would like to be storing integer values here.
I (roughly) understand that I am pretty okay with a straight cast up to around 2^23, but what if I want to go higher? Is there any way that I can take advantage of more of the 32 bits of a float and be sure I will get the same number back?
For clarification:
I'm doing some operations on point clouds with Pixar's PRMan (ie. RenderMan). I can write in either C or C++ linking against the precompiled point cloud API. PRMan at no point has to use these ints I am storing; I only need it to hand them back to me intact after operating on other data attached to the points.
So you cannot store a float value in an int object through simple assignment. You can store the bit pattern for a floating-point value in an int object if the int is at least as wide as the float , either by using memcpy or some kind of casting gymnastics (as other answers have shown).
float has 24 bits of precision (and a sign bit) which means you can store int values between -16777216 to 16777216 without loss of precision.
Scalars of type float are stored using four bytes (32-bits). The format used follows the IEEE-754 standard. The mantissa represents the actual binary digits of the floating-point number.
Integers and floats are two different kinds of numerical data. An integer (more commonly called an int) is a number without a decimal point. A float is a floating-point number, which means it is a number that has a decimal place.
Questionable:
In C, you can do the following, which is potentially unsafe (due to strict-aliasing rules):
int i = XXX;
float f;
*(int *)&f = i;
and which relies on the assumption that sizeof(int) == sizeof(float)
.
Less questionable:
Safer, but more longwinded, is the following:
int i = XXX;
float f;
memcpy(&f, &i, sizeof(int));
This still relies on matching data-type sizes. However, both of the above make the assumption that the internals of the library you're using will do nothing at all to the data. For instance, it won't have any special handling for NaN, or +/-infinity, etc.
Safe:
Along an entirely different train of thought, if you're happy to waste two floats per int, you could do something like:
int i = XXX;
float f[2] = { (i & 0xFFFF), ((unsigned)i >> 16 };
This last one is safe (other than some pretty reasonable assumptions on the size of floats and ints).
The mantissa field lets you store 23 bits. The exponent field lets you store almost 8 bits, it is 8 bits wide with a few values reserved. And there's a sign bit.
Avoiding the reserved values in the exponent, you can still store 31 bits of your choice.
You may find frexp
and ldexp
useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With