Boost C++ Libraries: Ticket #7886: Use 9 decimal digits for text serialization of float https://svn.boost.org/trac10/ticket/7886 <p> 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: </p> <pre class="wiki">void save(const float t) { os &lt;&lt; std::setprecision(std::numeric_limits&lt;float&gt;::digits10 + 2); ... } </pre><p> std::numeric_limits&lt;float&gt;::digits10+2=8, but float actually requires numeric_limits&lt;float&gt;::max_digits10=9 decimal digits to guarantee unique representation. </p> <p> In order to work around a bug in VS's max_digits10, it might be better to use numeric_limits&lt;T&gt;::digits * 3010 / 10000. See <a class="ext-link" href="http://boost.2283326.n4.nabble.com/serialization-Serialisation-deserialisation-of-floating-point-values-td2604169i20.html"><span class="icon">​</span>http://boost.2283326.n4.nabble.com/serialization-Serialisation-deserialisation-of-floating-point-values-td2604169i20.html</a> for details. </p> <p> 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. </p> <hr /> <p> The code below (with boost/1.52) demonstrates the problem: </p> <pre class="wiki">#include &lt;sstream&gt; #include "boost/archive/text_iarchive.hpp" #include "boost/archive/text_oarchive.hpp" #include &lt;iostream&gt; int main(int argc, char **argv){ float oldf = -1.20786635e-05; std::ostringstream os; boost::archive::text_oarchive oa(os); oa &amp; BOOST_SERIALIZATION_NVP(oldf); float newf; std::istringstream is(os.str()); boost::archive::text_iarchive ia(is); ia &amp; 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 </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/7886 Trac 1.4.3 Robert Ramey Wed, 21 Aug 2013 16:27:04 GMT <link>https://svn.boost.org/trac10/ticket/7886#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7886#comment:1</guid> <description> <p> patched in trunk </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Robert Ramey</dc:creator> <pubDate>Wed, 21 Aug 2013 16:58:34 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/7886#comment:2 https://svn.boost.org/trac10/ticket/7886#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> Ticket Daryle Walker Thu, 22 Aug 2013 02:01:30 GMT <link>https://svn.boost.org/trac10/ticket/7886#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/7886#comment:3</guid> <description> <p> In C++11, there are two additions to the <code>std::numeric_limits</code> class template. One of them, <code>max_digits10</code>, 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.) </p> </description> <category>Ticket</category> </item> </channel> </rss>