Jim Jim - 22 days ago 10
C# Question

Storing 2 Single Floats in One

I've read several links discussing storing 2 or 3 floats in one float. Here's an example:

Storing two float values in a single float variable

and another:

http://uncommoncode.wordpress.com/2012/11/07/float-packing-in-shaders-encoding-multiple-components-in-one-float/

and yet another:

decode rgb value to single float without bit-shift in glsl

I've seen others but all of them use the same principle. If you want to encode x and y, they multiply y by some factor and then add x to it. Well this makes since on paper, but I don't understand how in the world it can work when stored to a floating value. Floating values only have 7 significant digits. If you add a big number and a small number, the small number is just truncated and lost. The precision only shows the value of the big number.

Since everyone seems to prescribe the same method, I tried it myself and it did exactly what I thought it would do. When I decoded the numbers, the number that wasn't multiplied turned out as 0.0. It was completely lost in the encoded float.

Here's an example of some MaxScript I tried to test it:

cp = 256.0 * 256.0
scaleFac = 16777215

for i = 1 to 20 do (
for j = 1 to 20 do (
x = (i as float / 20.01f) as float;
y = (j as float / 20.01f) as float;
xScaled = x * scaleFac;
yScaled = y * scaleFac;

f = (xScaled + yScaled * cp) as float
print ("x[" + xScaled as string + "] y[" + yScaled as string + "]" + " e[" + f as string + "]")

dy = floor(f / cp)
dx = (f - dy * cp)

print ("x[" + dx as string + "] y[" + dy as string + "]" + " e[" + f as string + "]")
)
)


dx is 0.0 everytime. Can anyone shed some light on this? NOTE: It doesn't matter whether I make cp = 128, 256, 512 or whatever. It still gives me the same types of results.

Answer

This method works for storing two integers. You're effectively converting your floating point numbers to large integers by multiplying by scaleFac, which is good, but it would be better to make it explicit with int(). Then you need to make sure of two things: cp is greater than the largest number you're working with (scaleFac), and the square of cp is small enough to fit into a floating point number without truncation (about 7 digits for a single precision float).