10

Possible Duplicate:
Floating point inaccuracy examples

double a = 0.3;
std::cout.precision(20);
std::cout << a << std::endl;

result: 0.2999999999999999889

double a, b;
a = 0.3;
b = 0;
for (char i = 1; i <= 50; i++) {
  b = b + a;
};
std::cout.precision(20);
std::cout << b << std::endl;

result: 15.000000000000014211

So.. 'a' is smaller than it should be. But if we take 'a' 50 times - result will be bigger than it should be.

Why is this? And how to get correct result in this case?

Community
  • 1
  • 1
Davinel
  • 940
  • 4
  • 10
  • 20
  • 5
    Go and read about it. Floating-point issues need careful study so that you don't make dangerous mistakes. – Artelius May 26 '10 at 00:26
  • 1
    to have exact values use integers instead (or some bignum lib) const int acc=100; int tmp, a=30/acc, b=0; for (char i=1;i<=50;i++) b=b+a; std::cout << int(b/acc) << "."; tmp=b%acc; if (tmp<10) std::cout << "0"; std::cout << int (tmp); to speed things up you can use a power of 2 for acc so *,/,% converts to <<,>>,& – Spektre Aug 20 '13 at 13:07

5 Answers5

18

To get the correct results, don't set precision greater than available for this numeric type:

#include <iostream>
#include <limits>
int main()
{
        double a = 0.3;
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << a << std::endl;
        double b = 0;
        for (char i = 1; i <= 50; i++) {
                  b = b + a;
        };
        std::cout.precision(std::numeric_limits<double>::digits10);
        std::cout << b << std::endl;
}

Although if that loop runs for 5000 iterations instead of 50, the accumulated error will show up even with this approach -- it's just how floating-point numbers work.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
15

Why is this?

Because floating-point numbers are stored in binary, in which 0.3 is 0.01001100110011001... repeating just like 1/3 is 0.333333... is repeating in decimal. When you write 0.3, you actually get 0.299999999999999988897769753748434595763683319091796875 (the infinite binary representation rounded to 53 significant digits).

Keep in mind that for the applications for which floating-point is designed, it's not a problem that you can't represent 0.3 exactly. Floating-point was designed to be used with:

  • Physical measurements, which are often measured to only 4 sig figs and never to more than 15.
  • Transcendental functions like logarithms and the trig functions, which are only approximated anyway.

For which binary-decimal conversions are pretty much irrelevant compared to other sources of error.

Now, if you're writing financial software, for which $0.30 means exactly $0.30, it's different. There are decimal arithmetic classes designed for this situation.

And how to get correct result in this case?

Limiting the precision to 15 significant digits is usually enough to hide the "noise" digits. Unless you actually need an exact answer, this is usually the best approach.

dan04
  • 87,747
  • 23
  • 163
  • 198
  • Maybe you could add to the end of your first paragraph: "...because the infinite series of the binary representation of 0.3 is cut off at some point because infinite values cannot be stored on a computer". – josch Aug 18 '16 at 05:46
  • If one doesn't want to use a decimal arithmetic class, one should always store money in an integer type (possibly in one's own class) giving it units of cents or "thousandthsOfACent", as needed. This way, one always has the control of what to do with rounding errors, which only turn up in division, and are easily quantifiable. – Edward LeBlanc Apr 04 '22 at 16:13
8

Computers store floating point numbers in binary, not decimal.

Many numbers that look ordinary in decimal, such as 0.3, have no exact representation of finite length in binary.
Therefore, the compiler picks the closest number that has an exact binary representation, just like you write 0.33333 for 1⁄3.

If you add many floating-point numbers, these tiny difference add up, and you get unexpected results.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
1

It's not that it's bigger or smaller, it's just that it's physically impossible to store "0.3" as an exact value inside a binary floating point number.

The way to get the "correct" result is to not display 20 decimal places.

Dean Harding
  • 71,468
  • 13
  • 145
  • 180
-2

To get the "correct" result, try

List of Arbitrary-precision arithmetic Libraries from Wikipedia: http://en.wikipedia.org/wiki/Arbitrary-precision

or

http://speleotrove.com/decimal

Larry K
  • 47,808
  • 15
  • 87
  • 140
  • 2
    Decimal and arbitrary-precision arithmetic is most likely unnecessary for the OP's purposes. – dan04 May 26 '10 at 05:09