Boost logo

Boost Users :

Subject: Re: [Boost-users] [Serialization] XML: float format is scientific instead of human-readable since Boost 1.57
From: Paul A. Bristow (pbristow_at_[hidden])
Date: 2015-01-28 11:55:35


> -----Original Message-----
> From: Boost-users [mailto:boost-users-bounces_at_[hidden]] On Behalf Of
> Robert Ramey
> Sent: 28 January 2015 15:17
> To: boost-users_at_[hidden]
> Subject: Re: [Boost-users] [Serialization] XML: float format is scientific instead of
> human-readable since Boost 1.57
>
> Frank Stähr wrote
> > I compiled it with VS 2013 for 32 bit. The output file has the line:
> > <m_accuracy>
> > 2.99999999999999990e-002
> > </m_accuracy>
> > In Boost 1.55 it was much better human-readable: 0.03.
> >
> > Is this behaviour (this change) intended? In any case, what is the
> > best way to format floats and doubles? (i. e. a manipulator for the of
> > stream?)
>
> This is surely an unintended side effect of changes to guarantee correct "round
> tripping"
> of floating point numbers. That is that the the floating point number read in is bit for
> bit the same as the floating point number written out.
>
> This was seen as good thing.

Short answer:
If you want to be sure that what you get back from de-serialization is bit-for-bit identical to what you serialized,
then it is definitely a Good Thing.

For some MS compilers at least, it is also necessary to use scientific format for this to avoid some
very intermittent failures to 'round-trip' correctly. (This was discovered by a real-time user - and was only pinned down by random testing!)

Long Answer:
For more than you will want to know see:

Exploring Binary <exploringbinary_at_[hidden]>

And from a previous post:

> But the other thing is that by setting precision to 17 lexical_cast is
> bloating the string representations of the doubles with lots of 9s in
> both Visual Studio 2010 and Visual Studio 2013. Setting precision to
> 15 instead prevents this, and makes the original test run faster even with Visual Studio 2013 (about 4 seconds rather than 10).

In order to be sure of 'round-tripping' one needs to output std::numeric_limits<FPT>::max_digits10 decimal digits.

max_digits10 is 17 for double

enough to ensure that all *possibly* significant digits are used.

digits10 is 15 for double and using this will work for *your* example, but will fail to 'round-trip' exactly for *some* values of double.

The reason for a rewrite *might* be that for VS <=11, there was a slight 'feature'

('feature' according to Microsoft, 'bug' according to many, though the C++ Standard does NOT require round-tripping to be exact. Recent GCC and Clang achieve exact round-tripping.)

// The original value causing trouble using serialization was 0.00019075645054089487; // wrote 0.0019075645054089487 // read 0.0019075645054089489 // a increase of just 1 bit.

// Although this test uses a std::stringstream, it is possible that // the same behaviour will be found with ALL streams, including cout and cin?

// The wrong inputs are only found in a very narrow range of values:
// approximately 0.0001 to 0.004, with exponent values of 3f2 to 3f6 // and probably every third value of significand (tested using nextafter).

However, a re-test reveals that this 'feature' is still present using VS2013 (version 12.0).

(This tests uses random double values to find round-trip or loopback failures).

So the price of accuracy is lots of digits (and time to output and re-digest them) :-(

Paul

---
Paul A. Bristow
Prizet Farmhouse
Kendal UK LA8 8AB
+44 (0) 1539 561830
 

Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net