5
#include <iostream>
using namespace std;

int main()
{
    cout.precision(32);

    float val = 268433072;
    float add = 13.5;

    cout << "result =" << (val + add) << endl;
}

I'm compiling the above program with standard g++ main.cc
and running it with ./a.out

The ouput I receive however, is,
result =268433088

Clearly, this is not the correct answer..Why is this happening?

EDIT: This does not occur when using double in place of float

Guru Prasad
  • 4,053
  • 2
  • 25
  • 43
  • 9
    You might want to read [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). – Some programmer dude Jul 05 '13 at 18:42
  • Another good read on floating point issues: http://stackoverflow.com/questions/1089018/why-cant-decimal-numbers-be-represented-exactly-in-binary – mtrw Jul 05 '13 at 18:43
  • 3
    What behavior are you expecting instead? (I mean, from the fact that you tried both `float` and `double`, you obviously realize that `float` has limited precision . . .) – ruakh Jul 05 '13 at 18:43
  • 2
    Duplicate hundreds of times over.... – Carl Norum Jul 05 '13 at 18:43
  • I'm not sure I understand how or why there is a precision issue here..I'm not really asking for the program to try and add some infinite decimal sequence like `pi` – Guru Prasad Jul 05 '13 at 18:47
  • 2
    `268433088` or `2.68433088E8` is already quite a lot of decimal digits for a `float`. http://en.wikipedia.org/wiki/Significant_figures – Pascal Cuoq Jul 05 '13 at 18:50
  • That makes sense! Sorry for wasting everyone's time :/ It seems that I assumed float to be able to handle a number that large as an integer itself (since it is still lesser than 2^32 - 1)..What I didn't take into account was that float was already converting the large integer into a decimal and hence ran out of decimal places and ended up rounding off more than I expected – Guru Prasad Jul 05 '13 at 18:53
  • 1
    The problem is actually that float, to get its range and ability to store fractions, stores numbers in a binary version of scientific notation. It uses 9 bits for sign and exponent. That leaves 23 bits to actually store the significand. There is an additional bit that is always 1, and so does not have to be stored, for an effective 24 significant bits. Unless you have a lot of low precision data and know what you are doing, use double and firmly ignore float. Double can exactly store every 32 bit integer. – Patricia Shanahan Jul 05 '13 at 20:02
  • @user1761555: Re: "I assumed float to be able to handle a number that large as an integer itself": `float` and `int` are typically both 32 bits. `int` dedicates 1 bit to sign (`0` for nonnegative, `1` for negative) and 31 bits to precision; `float` dedicates 1 bit to sign, 8 bits to exponent, and 23 bits to precision. So there's a tradeoff: compared to `int`, `float` supports more non-integer values, but fewer *precise* integer values. – ruakh Jul 05 '13 at 20:09

2 Answers2

10

You can reproduce your "float bug" with an even simpler piece of code

#include <iostream>
using namespace std;

int main()
{
    cout.precision(32);
    float val = 2684330722;
    cout << "result =" << val << endl;
}

The output

result =2684330752

As you can see the output does not match the value val was initialized with.

As it has been stated many times, floating-point types have limited precision. Your code sample simply exceeded that precision, so the result got rounded. There's no "bug" here.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
1

Aside from the reference to (1991, PDF) What Every Computer Scientist Should Know About Floating-Point Arithmetic

The short answer is, that because float has limited storage (like the other primitives too) the engineers had to make a choice: which numbers to store with which precision. For the floating point formats they decided to store numbers of small magnitude precisely (some decimal digits), but numbers of large magnitude very imprecisely, in fact starting with +-16,777,217 the representable numbers are becoming so thin that not even all integers are represented which is the thing you noticed.

Bernd Elkemann
  • 23,242
  • 4
  • 37
  • 66