|
Boost : |
From: Greg Chicares (chicares_at_[hidden])
Date: 2001-02-20 19:18:20
Kevlin Henney wrote:
>
> In message <3A90B900.E6B07CE5_at_[hidden]>, Greg Chicares
> <chicares_at_[hidden]> writes
> >Would it be worthwhile to modify lexical_cast to reflect the inherent
> >precision of floating-point numbers?
>
> Possibly, if it can be done consistently and uniformly.
[snip some discussion]
> issues to address: (1) built-in casts do not always have value-
> preserving semantics (and hence are not always inverses),
Quite right. Conversion from double to int must truncate (4.9/1);
that is its nature. Yet conversion from int to double must be
value preserving if possible (4.9/2). Following that, I would
prefer that a lexical_cast from double to std::string be value
preserving insofar as that is possible. I see this particular
conversion--an inverse of atof(), if you will--as an especially
important application of lexical_cast.
> and (2) how
> practical is it to root out all of the edge cases?
Do you mean denormals, NaNs, and infinities? Is it too cavalier
to say "let them throw if they will"?
> >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.
>
> This works fine for float, double and long double, but have you tried it
> with std::complex? The results are unfortunate :-(
Thanks for pointing that out. Fixed below.
> digits10 is 0 for any non-specialised use of numeric_limits, which is
> the case for std::complex, which means that the stream is given an
> output precision of 1. So, other numeric types suffer as a result
Unacceptable, I agree.
> That said, there may be a solution if you select how you set the
> precision based on numeric_limits<>::is_specialized. This would
> discriminate in favour of built-ins, but at least would not actively
> discriminate against other types. However, I have not tried this
> approach out.
An approach that I believe is equivalent and simpler is to set the
precision to no less than the default of 6. This leads me to the
revised suggestion:
interpreter.precision
(std::max
(interpreter.precision()
,1 + static_cast<std::streamsize>
(
std::max
(std::numeric_limits<Source>::digits10
,std::numeric_limits<Target>::digits10
)
)
)
);
> A couple of other implementation issues you might also want to consider:
I think they can be addressed by adding these includes:
#ifdef BOOST_NO_LIMITS
# include <boost/pending/limits.hpp>
#else // BOOST_NO_LIMITS
# include <limits>
#endif // BOOST_NO_LIMITS
#ifndef BOOST_NO_STD_MIN_MAX
# include <algorithm>
#endif
> - std::max is not defined for MSVC, therefore must be done by hand.
I don't have that compiler, so I tried to simulate that behavior using
#define BOOST_NO_STD_MIN_MAX
before <boost/config.hpp> is included. It appears that the config file
supplies a correct implementation of std::max in this case.
> - <limits> is not defined for g++, so omit no support for this on g++.
I had grabbed <limits> from libstdc++-v3, but "modify your system headers"
isn't a good general approach.
I first thought to write a <limits> header, or at least the digits10
part (just returning DBL_MAX etc.), but I notice that's already been
done in /boost/boost_1_20_2/boost/pending/limits.hpp . Was that
copyrighted file intentionally included? If it's OK, then it could
be used with
cast.hpp
config.hpp
counting_iterator.hpp
integer.hpp
integer_traits.hpp
random.hpp
timer.hpp
all of which include <limits> .
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk