|
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