Correct (regardless of 32 bit / 64 bit) by storing the float in the binary stream

Thus, it is obvious that on my machine, the float, double and long double, each has different sizes. In addition, there is no strict standard to ensure how many bytes each of these types should be.

How would I save one floating point value in a binary file, and then is it correct to read it on another system if the sizes are different? for example, my machine has 8 bytes and joe has 12 bytes.

Without the need to export it in text form (for example, "0.3232"). Seems a lot less compact than binary representation.

+4
source share
3 answers

You must define the format and implement it. Typically, most of the network protocols that I know use IEEE float and double, output big-endian (but other formats are possible). The advantage of using IEEE formats is that it is what is used by most modern everyday machines inside; if you are on one of these machines (and portability for other machines, such as mainframes, is not a problem), you can "convert" to the format by simply using type-punning for an unsigned int of the same size and output. So, for example, you might have:

obstream& operator<<( obstream& dest, uint64_t value ) { dest.put((value >> 56) & 0xFF); dest.put((value >> 48) & 0xFF); dest.put((value >> 40) & 0xFF); dest.put((value >> 32) & 0xFF); dest.put((value >> 24) & 0xFF); dest.put((value >> 16) & 0xFF); dest.put((value >> 8) & 0xFF); dest.put((value ) & 0xFF); return dest; } obstream& operator<<( obstream& dest, double value ) { return dest << reinterpret_cast<uint64_t const&>( value ); } 

If you must be portable to a machine that does not support IEEE (for example, any of the modern mainframes), you will need something more complex:

 obstream& obstream::operator<<( obstream& dest, double value ) { bool isNeg = value < 0; if ( isNeg ) { value = - value; } int exp; if ( value == 0.0 ) { exp = 0; } else { value = ldexp( frexp( value, &exp ), 53 ); exp += 1022; } uint64_t mant = static_cast< uint64_t >( value ); dest.put( (isNeg ? 0x80 : 0x00) | exp >> 4 ); dest.put( ((exp << 4) & 0xF0) | ((mant >> 48) & 0x0F) ); dest.put( mant >> 40 ); dest.put( mant >> 32 ); dest.put( mant >> 24 ); dest.put( mant >> 16 ); dest.put( mant >> 8 ); dest.put( mant ); return dest; } 

(Note that this doesn’t handle NaN and infinities. Personally, I would forbid them from formatting, since not all floating-point representations support them. But then there is no floating-point format on the IBM mainframe that will support 1E306, although you can encode it in dual IEEE format above.)

Reading is, of course, the opposite. Or:

 ibstream& operator>>( ibstream& source, uint64_t& results ) { uint64_t value = (source.get() & 0xFF) << 56; value |= (source.get() & 0xFF) << 48; value |= (source.get() & 0xFF) << 40; value |= (source.get() & 0xFF) << 32; value |= (source.get() & 0xFF) << 24; value |= (source.get() & 0xFF) << 16; value |= (source.get() & 0xFF) << 8; value |= (source.get() & 0xFF) ; if ( source ) results = value; return source; } ibstream& operator>>( ibstream& source, double& results) { uint64_t tmp; source >> tmp; if ( source ) results = reinterpret_cast<double const&>( tmp ); return source; } 

or if you cannot rely on IEEE:

 ibstream& ibstream::operator>>( ibstream& source, double& results ) { uint64_t tmp; source >> tmp; if ( source ) { double f = 0.0; if ( (tmp & 0x7FFFFFFFFFFFFFFF) != 0 ) { f = ldexp( ((tmp & 0x000FFFFFFFFFFFFF) | 0x0010000000000000), static_cast<int>( (tmp & 0x7FF0000000000000) >> 52 ) - 1022 - 53 ); } if ( (tmp & 0x8000000000000000) != 0 ) { f = -f; } dest = f; } return source; } 

(This assumes the input is not NaN or infinity.)

+6
source

You can save them in a format that is machine independent. To do this, you first need to convert it from your view to another.

A simple form of conversion is to analyze a number in a triple (sign, exponent, value) and store them as integers. This way you can maintain complete accuracy.

+2
source

You can use Boost serialization http://www.boost.org/doc/libs/1_47_0/libs/serialization/doc/index.html , which can be serialized to text, xml or binary.

Otherwise, you can do it manually, for example, as follows:

  • You agree with the small endian (and check if the destination computer is too large or large than the recalculation).
  • you write one byte how many bytes the floating point number is long
  • then you write float to stream - how little endian
0
source

All Articles