boost property tree put/get DBL_MAX

2019-07-15 09:16发布

I'm programming a ptree and at some point I need to put DBL_MAX in (as a default value). I see the right number when I open the generated xml-file.

But when I use ptree.get to get the number an exception is thrown:conversion of data to type "d" failed

Here's my code:

using boost::property_tree::ptree;
ptree pt;

double d=-DBL_MAX;
double d2=-1.797693134862316e+308;
double d3=-1.79769e+308;

cout<<d<<endl;
cout<<d2<<endl;
cout<<d3<<endl;

pt.put<double>("double", d);
write_xml("test.xml", pt);

cout << "totalEndTimeLowerBound: " << pt.get<double>("double")<<endl;
//doesn't work with d and d2, but works with d3

What can cause this error and how can I resolve it?

1条回答
Deceive 欺骗
2楼-- · 2019-07-15 09:53

By default, ptree stores its values as std::string and convert them using basic_stringstream with precision:

s.precision(std::numeric_limits<double>::digits10+1);

This problem appears when it converts DBL_MAX to std::string because it rounds the number to an invalid value. You can check it with the following code:

ptree pt;
pt.put("min", -DBL_MAX);
pt.put("max", DBL_MAX);
cout << "Min=" << pt.get<string>("min") << std::endl;
cout << "Max=" << pt.get<string>("max") << std::endl;

Using Visual Studio, it prints:

Min=-1.797693134862316e+308

Max= 1.797693134862316e+308

However, DBL_MAX is defined as 1.7976931348623158e+308 so the printed value is out of limits.

There are several workarounds but none is perfect:

  • Use a different default value smaller than DBL_MAX. For example 1.797693134862315e+308.
  • Catch the bad_data exception and assume that it means default.
  • Register a new type with your custom converter. You can see an example here.
  • Reduce the precision of the stored value. You can perform this using the following code:

    namespace boost { namespace property_tree 
    {
      template <typename Ch, typename Traits>
      struct customize_stream<Ch, Traits, double, void>
      {
        static void insert(std::basic_ostream<Ch, Traits>& s, const double& e) {
          s.precision(std::numeric_limits<double>::digits10-1);
          s << e;
        }
        static void extract(std::basic_istream<Ch, Traits>& s, double& e) {
          s >> e;
          if(!s.eof()) {
            s >> std::ws;
           }
        }
      };
    }
    
查看更多
登录 后发表回答