I am writing a video game, Humm and Strumm, which requires a network component in its game engine. I can deal with differences in endianness easily, but I have hit a wall in attempting to deal with possible float
memory formats. I know that modern computers have all a standard integer format, but I have heard that they may not all use the IEEE standard for floating-point integers. Is this true?
While certainly I could just output it as a character string into each packet, I would still have to convert to a "well-known format" of each client, regardless of the platform. The standard printf()
and atod()
would be inadequate.
Please note, because this game is a Free/Open Source Software program that will run on GNU/Linux, *BSD, and Microsoft Windows, I cannot use any proprietary solutions, nor any single-platform solutions.
Cheers,
Patrick
Introduction to the Python float typeThe C double type usually implements IEEE 754 double-precision binary float, which is also called binary64. Python float uses 8 bytes (or 64 bits) to represent real numbers.
Python makes various references to IEEE 754 floating point operations, but doesn't guarantee 1 2 that it'll be used at runtime.
The standard specifies optional extended and extendable precision formats, which provide greater precision than the basic formats. An extended precision format extends a basic format by using more precision and more exponent range.
The IEEE Standard for Floating-Point Arithmetic (IEEE 754) is a technical standard for floating-point computation which was established in 1985 by the Institute of Electrical and Electronics Engineers (IEEE).
I think it is safe to assume that each platform has an implementation of the IEE-754 spec that you can rely on, however, even if they all implement the same spec there is no guarantee that each platform has the exact same implementation, has the same FP control flags set, does the same optimizations, or implements the same non-standard extensions. This makes floating point determinism very hard to control and somewhat unreliable to use for this kind of thing (where you'll be communicating FP values over the network).
For more information on that; read http://gafferongames.com/networking-for-game-programmers/floating-point-determinism/
Another problem to tackle is handling clients that don't have a floating point unit; most of the time these will be low-end CPUs, consoles or embedded devices. Make sure to take this into account if you want to target them. FP emulation can be done but tends to be very slow on these devices so you'll have to get a hang of doing fixed point calculations. Be advised though, writing elaborate classes to abstract floating point and fixed point calculations to the same code sounds like a plan; but on most devices isn't. It doesn't allow you to squeeze out the maximum precision and performance when dealing with fixed point values.
Yet another problem is handling the endianness of the floating point values because you cannot just swap bytes and stack 'm in a floating point register again (the bytes might get a different meaning, see http://www.dmh2000.com/cpp/dswap.shtml on that).
My advice would be to convert the floats to fixed point intermediate values, do an endian correction if needed and transmit that. Also, don't assume that two floating point calculations on different machines will yield the same results; they don't. However, floating point implementations other than IEEE-754 are rare. For example GPUs tended to use fixed point, but are more likely to have a subset of IEEE-754 these days because they don't want to deal with division-by-zero exceptions but they will have extensions for half-floats that fit in 16 bits.
Also realize that there are libraries out there that have already solved this problem (sending low-level data formats in a gaming context) for you. One such library is RakNet, specifically it's BitStream class is designed to send these kinds of data reliably to different platforms while keeping the overhead to a minimum; for example RakNet goes through quite some trouble not to waste any bandwidth on sending strings or vectors.
If you properly abstract your network interface, you can have functions/objects that serialize and deserialize the float datatypes. On every system I can think of, these are the IEEE standard, so you'd just have them pass the data through unchanged (the compiler will probably even optimize it out, so you don't lose any performance). If you do encounter some system with a different format, you can conditionally-compile in some code in these functions to do bit hacks to convert from the IEEE standard to the native format. You'll only need to change it in one place. You probably will never need to do so, however, unless you get into consoles/handhelds/etc.
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