Saving Floats
Michael Jensen

Ok, so a while back, I think KittyCat had posted, a method of saving floats (can't find it now) that basically involved some division, seperating it into two peices, and then saving each peice individually... it was kind of complicated but only like 5 lines or so of code... If anybody has any idea what I'm talking about, reposting this code would be greatly appreciated...

The reason for it, instead of just saving 4 bytes from memory was for cross platform compatability... (not all compilers adhere to the same standards or some such...)

Anyway, the reason I want it is because I'm writing a game in VB.NET (using allegro's file packing routines for saving data) that will save maps/tilesets to files on disk, and I need to save a single (a float is called a single in VB.) to a file. -- I've written some string/bitmap saving functions that seem to work pretty good, but saving with single.ToString()/loading with Single.Parse(x) is probably pretty bad for accuracy...

Help!

EDIT:
got the post: http://www.allegro.cc/forums/thread/525662

Kitty Cat said:

To save a float/double:
pack_iputl(file, floor(fval));if(fval-floor(fval)) pack_iputl(file, 1/(fval-floor(fval)));else pack_iputl(file, 0);
And to read:
long whole = pack_igetl(file);long recip = pack_igetl(file);float fval = whole + (recip ? (1.0/(float)recip) : 0.0);
Should work. To save an int, use pack_igetl/pack_iputl. For char, pack_getc/pack_putc.

Kitty Cat
1void save_float(PACKFILE *pf, float f)
2{
3 unsigned int recip;
4 int num = floor(f);
5 f -= (float)num;
6 recip = ((f != 0.0f) ? (unsigned int)(1.0/f): 0)
7 
8 pack_iputl(pf, num);
9 pack_iputl(pf, recip);
10}
11 
12float load_float(PACKFILE *pf)
13{
14 float f = (float)pack_igetl(pf);
15 unsigned int recip = pack_igetl(pf);
16 if(recip)
17 f += 1.0/recip;
18 return f;
19}

I can't gaurantee what kind of accurcy you'll get with that, though.

If you know the size of the float, and know that floats will be the same endianess as integers, you can use a cast, though:

void save_float(PACKFILE *pf, float f)
{
   pack_iputl(pf, *(uint32_t*)&f);
}

float load_float(PACKFILE *pf)
{
   int num = pack_igetl(pf);
   return *(float*)#
}

Michael Jensen

Since it's VB I can't guarantee the variable size of a single, or an int -- I got it working, and I also notice the evil accuracy. Thank you...

1/.34 = aprox 3, 1/3 = .333-> But that's good enough.

-- Does Floor always round towards 0, or round down?

Jonatan Hedborg

floor clips any decimals afaik.

Fladimir da Gorf

Floor rounds always down, ceil always up. A cast rounds towards zero.

Michael Jensen

Ok, so it seems like this will work with negative numbers also then -- that's good.

value = -3.5
fval = -4 {floor(value)}
pval = 2  {1/(value-fval)}
/* ---------------------------- */
output = -3.5 {fval + (1/pval)}

Looks good.

gillius

Every computer I have ever programed on uses IEEE-754 format -- Intel, PowerPC, Motorola, SPARC, UltraSPARC. You can just save the data in binary form. I don't know if software emulators for ARM use IEEE-754, but I wouldn't be surprised if they did.

If you are truly concerned about being able to load it, you can write an IEEE-754 loader in portable C or you can save as text.

Michael Jensen

When you save as text it rounds it anyway, and the only "binary" save method I have from the allegro packfile routines that doesn't require the data to be a pointer is save int32, int16, and int8 (char/byte) -- I could overload the int32 method to support single (float) and just hope that the marshalling converts it, but that could have some really evil side effects...

edit:
I wonder if there is a text-based math library out there (I know it would be slow, but imagine the accuracy, it could be used for high-precision calculator applications) -- by text based, I mean that a given number is stored in a string "4382749832432804327432.3213762173921873821739213" is probably a higher precision number than most numeric types would allow for instance, but string, who cares? -- obviously all the math would have to be done in software, and it would be painfully slow compared to hardware math.

gillius

You don't have to do rounding to print out a float. The Java language I believe specifies that a float is printed to contain exactly the number of digits that it takes to completely distinguish one float from another, and no more. In this manner, printing a float as text and reading it back in is an exact copy.

Michael Jensen

Hmmm... I guess that makes sense -- There is probably a way in VB.NET also, probably one of the ToString() format strings... I'll have to look into that. I guess I'm just soo used to string formatters messing with my floats...

Thread #565997. Printed from Allegro.cc