Opened 10 years ago

Closed 9 years ago

Last modified 9 years ago

#7886 closed Bugs (fixed)

Use 9 decimal digits for text serialization of float

Reported by: Adam Lerer <adam.lerer@…> Owned by: Robert Ramey
Milestone: To Be Determined Component: serialization
Version: Boost 1.52.0 Severity: Problem
Keywords: Cc:

Description

The boost serialization of float doesn't appear to use enough digits to guarantee that deserialization of a serialized float will produce the same value. The relevant code is in boost/archive/basic_text_oprimitive.hpp:

void save(const float t)
{
    os << std::setprecision(std::numeric_limits<float>::digits10 + 2);
    ... 
}

std::numeric_limits<float>::digits10+2=8, but float actually requires numeric_limits<float>::max_digits10=9 decimal digits to guarantee unique representation.

In order to work around a bug in VS's max_digits10, it might be better to use numeric_limits<T>::digits * 3010 / 10000. See http://boost.2283326.n4.nabble.com/serialization-Serialisation-deserialisation-of-floating-point-values-td2604169i20.html for details.

On the boost mailing list, it was correctly pointed out that serializing floating-point to text cannot always be guaranteed to deserialize to the same value (e.g. across architectures), but for the common case, 9 digits is what is required to guarantee correct roundtrip serialization. Also, other libraries like boost::lexical_cast use 9 digits.


The code below (with boost/1.52) demonstrates the problem:

#include <sstream>
#include "boost/archive/text_iarchive.hpp"
#include "boost/archive/text_oarchive.hpp"
#include <iostream>

int main(int argc, char **argv){
float oldf = -1.20786635e-05;
std::ostringstream os;
boost::archive::text_oarchive oa(os);
oa & BOOST_SERIALIZATION_NVP(oldf);

float newf;
std::istringstream is(os.str());
boost::archive::text_iarchive ia(is);
ia & BOOST_SERIALIZATION_NVP(newf);
printf("before serialization: %.12g\nafter serialization:  %.12g\n", oldf, newf);
}

///Output:
///before serialization: -1.20786635307e-05
///after serialization:  -1.20786644402e-05

Change History (3)

comment:1 by Robert Ramey, 9 years ago

patched in trunk

comment:2 by Robert Ramey, 9 years ago

Resolution: fixed
Status: newclosed

comment:3 by Daryle Walker, 9 years ago

In C++11, there are two additions to the std::numeric_limits class template. One of them, max_digits10, seems to exist to solve this problem. In fact, Boost.Test uses that datum when compiled in C++11 mode. (Which caused a problem in Boost.Rational because it wasn't updated for many years.)

Note: See TracTickets for help on using tickets.