-1

EDIT: There are a lot of disgruntled members here because this question had a duplicate on the site. In my defense, I tried searching for the answer FIRST, and maybe I was using poor searching keywords, but I could not find a direct, clear answer to this specific code example. Little did I know there was one out there from **2009** that would then be linked to from here.

Here's a coded example:

#include <iostream>
using namespace std;

int main() {
    float x = 0.1 * 7;
    if (x == 0.7)
        cout << "TRUE. \n";
    else
        cout << "FALSE. \n";

    return 0;
}

This results in FALSE. However, when I output x, it does indeed output as 0.7. Explanation?

The Rationalist
  • 743
  • 1
  • 10
  • 23

4 Answers4

7

Please read What Every Computer Scientist Should Know About Floating-Point Arithmetic.

First of all, 0.1 is a literal of type double. The closest representable value to 0.1 in IEEE 754 double-precision is:

0.1000000000000000055511151231257827021181583404541015625

If you multiply that by 7, the closest representable value in IEE 754 single-precision (since you're storing it in a float) is:

0.699999988079071044921875

Which, as you can see, is almost 0.7, but not quite. This then gets converted to a double for the comparison, and you end up comparing the following two values:

0.699999988079071044921875 == 0.6999999999999999555910790149937383830547332763671875

Which of course evaluates to false.

Stephen Canon
  • 103,815
  • 19
  • 183
  • 269
Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Actually, the closest IEEE double for 0.1 is 0.1000000000000000055511151231257827021181583404541015625 (3602879701896397 * 2^-55) – Chris Dodd Apr 28 '13 at 21:40
  • @ChrisDodd Thanks, I imagine the site I was using gave me the wrong value for 0.7 as a double too then. – Joseph Mansfield Apr 28 '13 at 21:46
  • 1
    A super minor remark: the program does not mathematically multiply `0.1000000000000000055511151231257827021181583404541015625` by `7` and then rounds that to `float`, as you seem to imply. It mathematically multiplies `0.1000000000000000055511151231257827021181583404541015625` by `7`, rounds that to `double` (these two operations are compounded in the `double` multiplication) **and then** rounds that to `float`. Statistically, it rarely makes a difference but it can make one. – Pascal Cuoq Apr 29 '13 at 08:56
  • 1
    @PascalCuoq: it might do that, or it might multiply them and round to long double, then round to float, or it might do something else entirely. You know this, of course. – Stephen Canon Apr 29 '13 at 15:10
  • @StephenCanon I should have said “to `double` or to `long double`” and suggest we collectively refuse to acknowledge compilers that do not do one or the other. And the `long double` is only because of a customer we serve. – Pascal Cuoq Apr 29 '13 at 18:53
1

This is because numbers are stored in binary. In binary, you cannot exactly represent the fraction .1 or .7 with finitely many places, because these have repeating expansions in binary. something like 1/2 can be represented exactly with the representation .1, but .1 in decimal for instance is .0001100110011.... So, when you cut off this number, you're bound to have roundoff error.

marcelo827
  • 44
  • 4
0

Doubles and floats should never be compared by the == operator. Numbers are stored in memory inaccurately because in binary they don't have to have finite representation (for example 0.1).

You will see it here:

#include <iostream>
using namespace std;

int main() {
    float x = 0.1 * 7;
    cout << x-0.7;
    return 0;
}

The difference is NOT zero, but something very very close to zero.

Martin P
  • 39
  • 1
  • 2
  • 7
0

Like every datatype a float is represented as binary number. For the exact representation see here: http://en.wikipedia.org/wiki/IEEE_floating_point

When converting a decimal number to a floating point number by hand, you first have to convert it to a fixed point number.

Converting 0.7 to base 2 (binary):

0.7 = 0.101100110011...

As you see it has infinite digits after the comma, so when representing it as a float datatype, some digits will get cut off. This results in the number not being EXACTLY 0.7 when converting it back to decimal.

In your example the multiplication results in a different number than the literal "0.7".

To fix this: Use a epsilon when comparing equality of floats:

if (x < 0.71f && x > 0.69f)
typ1232
  • 5,535
  • 6
  • 35
  • 51