Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Saving Floats

This thread is locked; no one can reply to it. rss feed Print
Saving Floats
Michael Jensen
Member #2,870
October 2002
avatar

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
Member #2,815
October 2002
avatar

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*)#
}

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Michael Jensen
Member #2,870
October 2002
avatar

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
Member #4,886
July 2004
avatar

floor clips any decimals afaik.

Fladimir da Gorf
Member #1,565
October 2001
avatar

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

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Michael Jensen
Member #2,870
October 2002
avatar

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
Member #119
April 2000

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.

Gillius
Gillius's Programming -- https://gillius.org/

Michael Jensen
Member #2,870
October 2002
avatar

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
Member #119
April 2000

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.

Gillius
Gillius's Programming -- https://gillius.org/

Michael Jensen
Member #2,870
October 2002
avatar

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...

Go to: