Boost logo

Boost :

From: Greg Chicares (chicares_at_[hidden])
Date: 2001-02-19 01:11:12


Would it be worthwhile to modify lexical_cast to reflect the inherent
precision of floating-point numbers?

I believe that
  lexical_cast<std::string, PODType)
and
  lexical_cast<PODType, std::string)
are already inverse operations for non-floating-point POD types. The
motivation is to make that true--or, equivalently, to make lexical_cast
a value-preserving conversion--for floating-point types as well.

I believe it suffices to add
  const int prec0 = std::numeric_limits<Source>::digits10;
  const int prec1 = std::numeric_limits<Target>::digits10;
  interpreter.precision(1 + max(prec0, prec1)); // see Notes
to lexical_cast.hpp right after 'interpreter' is defined. Thus, for
double d, this statement would be true:
  d == lexical_cast<double>(lexical_cast<std::string>(d));
except in degenerate cases like NANs.

Notes:
[1] <algorithm> should be included to use 'std::max'.
[2] 'digits10' is only a lower bound; for some floating-point values,
one more base 10 digit can be represented without change.

Here is a demonstration of my concerns:

  #include <iostream>
  #include <limits>
  #include <string>
  #include <boost/lexical_cast.hpp>
  using boost::lexical_cast;

  int main()
  {
   // These doubles ought to be equal.
    double d0(123456789.0123456);
    std::string s0(lexical_cast<std::string>(d0));
    double d1(lexical_cast<double>(s0));
    std::cout << "d0 " << ((d0 == d1) ? "==" : "!=") << " d1\n";

   // If double suffices to represent any long int exactly...
    const int long_digits = std::numeric_limits<long int>::digits;
    const int double_digits = std::numeric_limits<double>::digits;
    bool exact = long_digits <= double_digits;
    std::cout << "double can represent long int exactly: "
      << exact << '\n';
   // ...then (double)long_int_value ought to equal long_int_value...
    const long int m = std::numeric_limits<long int>::max();
    std::string s2(lexical_cast<std::string>(m));
   // ...but (double) on the next line is in effect a
   // narrowing conversion when we cast to string and back when
   // numeric_limits<long int>::digits
   // exceeds the default ios precision.
    std::string s3(lexical_cast<std::string>((double)m));
    double d2(lexical_cast<double, std::string>(s2));
    double d3(lexical_cast<double, std::string>(s3));
    const int prec = 1 + std::numeric_limits<double>::digits10;
    std::cout.precision(prec);
    std::cout.setf(ios::fixed, ios::floatfield);
    cout << d2 << '\n' << d3 << '\n';

   // This ought not to throw.
    double d4(std::numeric_limits<long int>::max());
    lexical_cast<long int>(d4);
  }

On my PC, this produces:

  d0 != d1
  double can represent long int exactly: 1
  2147483647.0000000000000000
  2147480000.0000000000000000

  abnormal program termination

with gcc-2.95.2, and equivalent results with borland C++ 5.5 .
With the suggested change, both compilers produce:

  d0 == d1
  double can represent long int exactly: 1
  2147483647.0000000000000000
  2147483647.0000000000000000


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk