Topic: Rounding by cout and printf
Author: kanze@gabi-soft.fr
Date: Wed, 10 Nov 2004 17:26:09 GMT Raw View
pbristow@hetp.u-net.com ("Paul A Bristow") wrote in message
news:<1100018129.798.0@damia.uk.clara.net>...
> "Falk Tannh user" <tannhauser86549spam@free.fr> wrote in message
> news:418c003f$0$7307$636a15ce@news.free.fr...
> > Paul A Bristow wrote:
> > > Is this behaviour the most reasonable or helpful?
> > > Is the fact that numeric_limits rounding style for
> > > double is round_to_nearest irrelevant?
> > > Is this behaviour really Standard?
> > The problem is that there are *two* rounding operations going on,
> > the first one from the decimal representation of the floating point
> > literal to the binary representation of 'double', then the second
> > one from the latter back to decimal representation on output.
> I agree with this, but would it not be helpful if the roundings
> cancelled out so that you 'got back' nearer to what you input?
As Falk pointed out, there is a loss of information in the first
rounding. Once the information has been lost, there's no way to get it
back.
Think about it for a moment. On my machine, a double has 64 bits, of
which 52 are mantissa. The character sequence "9.5" has 24 bits, of
which 16 are "mantissa". What you are asking for is a way of storing 52
bits in 16 bits, and still being able to recover the original 52 bits.
It's provably impossible.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sjhoweATdialDOTpipexDOTcom@eu.uu.net ("Stephen Howe")
Date: Wed, 10 Nov 2004 18:17:31 GMT Raw View
> I agree with this, but would it not be helpful if the roundings cancelled
> out so that you 'got back' nearer to what you input?
It won't work. There is no way of knowing of the chip given 2 fp numbers in
binary format that differ by 1 in the least significant bit of the mantissa
which decimal format number you had in mind.
When the compiler compiles a textual representation of a floating point
number, it is read and converted from a decimal format to a binary format.
At this point, for most fp numbers, information of the exact decimal number
is lost. In converting back from binary format to decimal format (and this
tep can be done without loss of information), where is the chip going to get
hold of the original information that was lost?
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Wed, 10 Nov 2004 18:19:03 GMT Raw View
tannhauser86549spam@free.fr (Falk Tannh user) wrote in message
news:<418c003f$0$7307$636a15ce@news.free.fr>...
> Paul A Bristow wrote:
[...]
> When you really need to avoid the problems you describe (which is
> certainly necessary for financial calculations), you have to avoid
> performing of two rounding operations due to converting decimal
> floating point => binary floating point => decimal floating point, and
> thus, you should avoid floating point altogether, or perhaps use some
> BCD floating point library.
When you really need to avoid the problems he described... you have an
impossible problem. (Or rather, the solution involves using more digits
in the intermediate representations.) Decimal arithmetic doesn't help.
Once you've converted a price in Francs into Euros AND rounded to the
two digits after the decimal, there is no way to recover the original
price in Francs.
The problem can only be avoided by means of extra digits. (The EU
requires the conversion to Euros to be done to five digits after the
decimal. Presumably, if you don't throw this digits out, you can
recover the original value. Provided it wasn't more precise than
centimes, at least.)
The reason for using decimal is slightly different. Legally sanctionned
bookkeeping practice defines very precisely how the rounding (and thus
the information loss) is to take place. And it defines it according to
decimal arithmetic. If you use IEEE double, the results may be even
more exact, but they won't conform to what the local law requires.
There is, too, the intuitive aspect, and the fact that we input and
output in decimal. If I say that the arithmetic is done to two digits
behind the decimal, everyone finds it perfectly normal that 1/3 is .33,
even though .33*3 does not give 1.00. Do the same thing in binary, and
people find it counter-intuitive.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Michiel.Salters@logicacmg.com (Michiel Salters)
Date: Thu, 11 Nov 2004 19:39:19 GMT Raw View
kanze@gabi-soft.fr wrote in message news:<d6652001.0411100258.18ae82d9@posting.google.com>...
> tannhauser86549spam@free.fr (Falk Tannh user) wrote in message
> news:<418c003f$0$7307$636a15ce@news.free.fr>...
> > Paul A Bristow wrote:
>
> [...]
> > When you really need to avoid the problems you describe (which is
> > certainly necessary for financial calculations), you have to avoid
> > performing of two rounding operations due to converting decimal
> > floating point => binary floating point => decimal floating point, and
> > thus, you should avoid floating point altogether, or perhaps use some
> > BCD floating point library.
> The problem can only be avoided by means of extra digits. (The EU
> requires the conversion to Euros to be done to five digits after the
> decimal. Presumably, if you don't throw this digits out, you can
> recover the original value. Provided it wasn't more precise than
> centimes, at least.)
>
> The reason for using decimal is slightly different. Legally sanctionned
> bookkeeping practice defines very precisely how the rounding (and thus
> the information loss) is to take place. And it defines it according to
> decimal arithmetic. If you use IEEE double, the results may be even
> more exact, but they won't conform to what the local law requires.
But does this mean one has to use decimal floating point? As I understand
it, the ECB rules mean you can work in integral milli-cents. Rounding
rules still may be a problem, but at least the custom rounding logic is
easier when working on integers.
Regards,
Michiel Salters
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kanze@gabi-soft.fr
Date: Fri, 12 Nov 2004 23:30:12 GMT Raw View
Michiel.Salters@logicacmg.com (Michiel Salters) wrote in message
news:<fcaee77e.0411110047.9bb16a2@posting.google.com>...
> kanze@gabi-soft.fr wrote in message
> news:<d6652001.0411100258.18ae82d9@posting.google.com>...
> > tannhauser86549spam@free.fr (Falk Tannh user) wrote in message
> > news:<418c003f$0$7307$636a15ce@news.free.fr>...
> > > Paul A Bristow wrote:
> > [...]
> > > When you really need to avoid the problems you describe (which is
> > > certainly necessary for financial calculations), you have to avoid
> > > performing of two rounding operations due to converting decimal
> > > floating point => binary floating point => decimal floating point,
> > > and thus, you should avoid floating point altogether, or perhaps
> > > use some BCD floating point library.
> > The problem can only be avoided by means of extra digits. (The EU
> > requires the conversion to Euros to be done to five digits after the
> > decimal. Presumably, if you don't throw this digits out, you can
> > recover the original value. Provided it wasn't more precise than
> > centimes, at least.)
> > The reason for using decimal is slightly different. Legally
> > sanctionned bookkeeping practice defines very precisely how the
> > rounding (and thus the information loss) is to take place. And it
> > defines it according to decimal arithmetic. If you use IEEE double,
> > the results may be even more exact, but they won't conform to what
> > the local law requires.
> But does this mean one has to use decimal floating point? As I
> understand it, the ECB rules mean you can work in integral
> milli-cents. Rounding rules still may be a problem, but at least the
> custom rounding logic is easier when working on integers.
I don't think you actually need floating point, and of course,
calculations using integral millicents are effectively decimal fixed
point. I was simply responding in the given context to the statement
that using decimal somehow avoids rounding problems. The rounding
problems are present whenever finite precision is involved. The only
advantage with regards to decimal is that the legally imposed rules for
rounding financial calculations are expressed in terms of decimal
arithmetic.
--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orient e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S mard, 78210 St.-Cyr-l' cole, France, +33 (0)1 30 23 00 34
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: news@news.demon.net ("News Admin")
Date: Mon, 15 Nov 2004 19:49:15 GMT Raw View
Don't forget the work being done by Mike Cowlishaw and others
to add decimal floating-point arithmetic to C and C++
WG14/N1016, and a critique in WG21/N1567
Hopefully it will become possible to avoid some of these rounding issues in
future.
Roger Orr
--
MVP in C++ at www.brainbench.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pbristow@hetp.u-net.com ("Paul A Bristow")
Date: Fri, 5 Nov 2004 06:17:38 GMT Raw View
If I write
double d = 9.95;
cout << setprecision(3) << d << endl; // Output is 9.95
cout << setprecision(2) << d << endl; // Output is 9.9
// or similarly using printf
but I might expect precision(2) to round 9.95 up to 10.
The reason, of course, is that the nearest floating point representation for
9.95 is
9.9499999999999993 using precision (17) (all significant decimal digits)
or hex 4023e666 66666666
and it fails to round-up 4 followed by anything.
The next higher representable value is
9.9500000000000011 4023e666 66666667
and cout and printf round these to 10., as expected by anyone.
(And there are, of course, many similar examples like this).
Is this behaviour the most reasonable or helpful?
Is the fact that numeric_limits rounding style for
double is round_to_nearest irrelevant?
Is this behaviour really Standard?
--
Paul A Bristow
Prizet Farmhouse, Kendal LA8 8AB UK
pbristow@hetp.u-net.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: barmar@alum.mit.edu (Barry Margolin)
Date: Fri, 5 Nov 2004 20:51:35 GMT Raw View
In article <1099604933.14366.0@spandrell.news.uk.clara.net>,
pbristow@hetp.u-net.com ("Paul A Bristow") wrote:
> If I write
>
> double d = 9.95;
> cout << setprecision(3) << d << endl; // Output is 9.95
> cout << setprecision(2) << d << endl; // Output is 9.9
> // or similarly using printf
>
> but I might expect precision(2) to round 9.95 up to 10.
>
> The reason, of course, is that the nearest floating point representation for
> 9.95 is
>
> 9.9499999999999993 using precision (17) (all significant decimal digits)
>
> or hex 4023e666 66666666
>
> and it fails to round-up 4 followed by anything.
>
> The next higher representable value is
>
> 9.9500000000000011 4023e666 66666667
>
> and cout and printf round these to 10., as expected by anyone.
>
> (And there are, of course, many similar examples like this).
>
> Is this behaviour the most reasonable or helpful?
What else can it do? By the time cout/printf is used, it can't tell
whether you entered 'd = 9.95' or 'd = 9.949999999999999'. Both of
these will result in the same binary floating point value.
Face it, floating point is inherently inaccurate, and you shouldn't
expect it to behave intuitively.
--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: tannhauser86549spam@free.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Sat, 6 Nov 2004 18:38:28 GMT Raw View
Paul A Bristow wrote:
> Is this behaviour the most reasonable or helpful?
>
> Is the fact that numeric_limits rounding style for
> double is round_to_nearest irrelevant?
>
> Is this behaviour really Standard?
The problem is that there are *two* rounding operations
going on, the first one from the decimal representation
of the floating point literal to the binary representation
of 'double', then the second one from the latter back to
decimal representation on output.
On a typical implementation, where
sizeof(double) == 8
std::numeric_limits<double>::digits == 53
std::numeric_limits<double>::digits10 == 15
the following variable definitions will likely yield the
same binary representation:
double d0 = 9.95;
double d1 = 9.9499999999999985;
double d2 = 9.9500000000000001;
i.e. (d1 == d2) will hold and some of the information
contained within the floating point literals is lost -
there is no means to make
std::cout << d1 << ' ' << d2 << '\n';
display two different values, no matter what precision
or formatting flags are used. The precise decimal
representation of d0, d1 and d2 as initialised above would be
9.9499999999999992894572642398998141288757324218750 (or
1001.1111001100110011001100110011001100110011001100110 binary),
and the next bigger 'double' value would be precisely
9.9500000000000010658141036401502788066864013671875 (or
1001.1111001100110011001100110011001100110011001100111 binary),
(the difference between them is 2 ^ -49 or
0.0000000000000017763568394002504646778106689453125 ,
4 of the 53 mantissa bits being used for representing the
"integer part").
When decimally outputting d0, d1 or d2 with a precision of 1,
rounding down to 9.9 is certainly the only reasonable option.
When you really need to avoid the problems you describe (which
is certainly necessary for financial calculations), you have to
avoid performing of two rounding operations due to converting
decimal floating point => binary floating point => decimal
floating point, and thus, you should avoid floating point
altogether, or perhaps use some BCD floating point library.
Falk
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pbristow@hetp.u-net.com ("Paul A Bristow")
Date: Tue, 9 Nov 2004 17:59:46 GMT Raw View
"Falk Tannh user" <tannhauser86549spam@free.fr> wrote in message
news:418c003f$0$7307$636a15ce@news.free.fr...
> Paul A Bristow wrote:
>
> > Is this behaviour the most reasonable or helpful?
> >
> > Is the fact that numeric_limits rounding style for
> > double is round_to_nearest irrelevant?
> >
> > Is this behaviour really Standard?
>
> The problem is that there are *two* rounding operations
> going on, the first one from the decimal representation
> of the floating point literal to the binary representation
> of 'double', then the second one from the latter back to
> decimal representation on output.
I agree with this, but would it not be helpful if the roundings cancelled
out so that you 'got back' nearer to what you input?
Could Floating point 'rounding control' be employed to control this?
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: tannhauser86549spam@free.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Tue, 9 Nov 2004 23:24:16 GMT Raw View
Paul A Bristow wrote:
> I agree with this, but would it not be helpful if the roundings cancelled
> out so that you 'got back' nearer to what you input?
>
> Could Floating point 'rounding control' be employed to control this?
But 9.9499999999999992894572642398998141288757324218750 *IS* already the
nearest representable 'double' (assuming 53 bit mantissa) approximating 9.95
- the next bigger representable 'double' 9.9500000000000010658141036401502788066864013671875
is further away, and the compiler, when converting the floating point literal
to the internal representation, cannot generally know that you wish
- to output the number with 1 digit precision after decimal point,
- it to be rounded to "10.0" rather than "9.9" in this case.
If you could instruct the compiler by some means to choose the
bigger one of the representable neighbours of a decimal floating
point literal, even if the representation error is greater,
it would give lower precision and unexpected/undesired results
in other cases.
Falk
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]