This is the mail archive of the
gcc-prs@gcc.gnu.org
mailing list for the GCC project.
libstdc++/5875: operator<<(double) doesn't allow printing full precision (3.0 regression)
- From: snyder at fnal dot gov
- To: gcc-gnats at gcc dot gnu dot org
- Date: Thu, 7 Mar 2002 15:13:35 -0600
- Subject: libstdc++/5875: operator<<(double) doesn't allow printing full precision (3.0 regression)
- Reply-to: snyder at fnal dot gov
>Number: 5875
>Category: libstdc++
>Synopsis: operator<<(double) doesn't allow printing full precision (3.0 regression)
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: unassigned
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Mar 07 13:26:02 PST 2002
>Closed-Date:
>Last-Modified:
>Originator: scott snyder
>Release: 3.1 20020303 (prerelease)
>Organization:
>Environment:
System: Linux karma 2.4.9-13 #1 Tue Oct 30 20:11:04 EST 2001 i686 unknown
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ../egcs/configure --prefix=/usr/local/egcs --enable-threads=posix --enable-long-long --enable-languages=c,c++,f77 : (reconfigured)
>Description:
We have code that expects, after suitably widening the precision,
to be able to write out a double to a stream using operator<<,
then read it back using operator>> and get the same value to within
a relative error of DBL_EPSILON. This used to be the case with gcc 3.0,
but is no longer true with gcc 3.1.
A little test program is below.
When i build this (on linux/ia86) with gcc 3.0.2, it prints `0'.
But when i build this with the gcc 3.1 branch, it prints `-3.10862e-15'.
So this is a relative error of about 1e-15, which is about 5 times
larger than DBL_EPSILON.
This comes about because the precision that the user specifies is clamped
to a maximum of numeric_limits<T>::digits10. However, this is the floor
of the `true' fractional value --- limiting yourself to that many digits
can lose a couple bits off the end.
Several years ago, i submitted a patch to increase this limit by a couple
to avoid this problem:
2000-03-29 scott snyder <snyder@fnal.gov>
* bits/locale_facets.tcc (do_put): Allow a couple extra digits of
precision beyond that which we get from numeric_limits::digits10.
However, it looks like when the locale code was revised between 3.0 and 3.1,
this change got lost.
Below is a patch to fix this (along with an addition to the testsuite,
so that it doesn't get lost again).
>How-To-Repeat:
-- x.cc ------------------------------------------------------------------
#include <sstream>
#include <iostream>
#include <string>
int main ()
{
double pi = 3.14159265358979323846;
std::ostringstream ostr;
ostr.precision(20);
ostr << pi;
std::string sval = ostr.str();
std::istringstream istr (sval);
double d;
istr >> d;
std::cout << d - pi << "\n";
return 0;
}
--------------------------------------------------------------------------
>Fix:
2002-03-06 scott snyder <snyder@fnal.gov>
* include/bits/locale_facets.tcc (num_put::_M_convert_float):
Allow one more digit of precision.
* testsuite/27_io/ostream_inserter_arith.cc: Test that we can
write a double and read back in the same value.
Index: include/bits/locale_facets.tcc
===================================================================
RCS file: /cvs/gcc/egcs/libstdc++-v3/include/bits/locale_facets.tcc,v
retrieving revision 1.63.2.3
diff -u -p -r1.63.2.3 locale_facets.tcc
--- locale_facets.tcc 2002/03/05 19:05:05 1.63.2.3
+++ locale_facets.tcc 2002/03/07 19:43:29
@@ -610,7 +610,9 @@ namespace std
_M_convert_float(_OutIter __s, ios_base& __io, _CharT __fill, char __mod,
_ValueT __v) const
{
- const int __max_digits = numeric_limits<_ValueT>::digits10;
+ // Note: digits10 is rounded down. We need to add 1 to ensure
+ // we get the full available precision.
+ const int __max_digits = numeric_limits<_ValueT>::digits10 + 1;
streamsize __prec = __io.precision();
// Protect against sprintf() buffer overflows.
if (__prec > static_cast<streamsize>(__max_digits))
>Release-Note:
>Audit-Trail:
>Unformatted: