Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Portable serialisation of IEEE754 floating-point values

I've recently been working on a system that needs to store and load large quantities of data, including single-precision floating-point values. I decided to standardise on network byte order for integers, and also decided to store floating point values in big-endian format, i.e.:

  |-- Byte 0 --| |-- Byte 1 -|  Byte 2   Byte 3
  #      ####### #     ####### ######## ########
Sign     Exponent          Mantissa
 1b    8b, MSB first    23b, MSB first

Ideally, I want to provide functions like htonl() and ntohl(), since I have already been using these for swabbing integers, and I also want to implement this in a way that has as much platform-independence as possible (while assuming that the float type corresponds to IEEE754 32-bit floating point values). Is there some way, possibly using ieee754.h, to do this?

I have one answer that seems to work, and I will post it below, but it seems pretty slow and inefficient and I would appreciate any suggestions about how to make it faster and/or more reliable.

like image 661
Peter T.B. Brett Avatar asked May 16 '12 14:05

Peter T.B. Brett


People also ask

What is IEEE 754 32 bit single-precision floating point numbers?

IEEE single-precision floating-point format. The format of IEEE single-precision floating-point standard representation requires 23 fraction bits F, 8 exponent bits E, and 1 sign bit S, with a total of 32 bits for each word. F is the mantissa in 2's complement positive binary fraction represented from bit 0 to bit 22.

How many values can floating-point represent?

Over the entire typical float range, about 232 different values can be represented.

What is a floating-point 32?

Single-precision floating-point format (sometimes called FP32 or float32) is a computer number format, usually occupying 32 bits in computer memory; it represents a wide dynamic range of numeric values by using a floating radix point.


1 Answers

Much simpler, and depending on the same assumption as yours (which is that float and integer types have the same byte order, and is almost universally valid -- realistically you'll never encounter a system where it isn't true):

#include <string.h>

float htonf(float val) {
    uint32_t rep;
    memcpy(&rep, &val, sizeof rep);
    rep = htonl(rep);
    memcpy(&val, &rep, sizeof rep);
    return val;
}

Any reasonably good compiler will optimize away the two memcpy calls; they are present to defeat over-eager strict aliasing optimizations, so this ends up being as efficient as htonl plus the overhead of a single function call.

like image 105
Stephen Canon Avatar answered Oct 09 '22 09:10

Stephen Canon