M Smith
M Smith

Reputation: 430

Why does this float type value output in this way?

I've been following some online C++ tutorials recently, and have found myself at a loss for what is going on here in one of the code examples. They have used the variable float f = 3.33333333333333333333333333333333333333f; and then output it; setting the precision equal to 16sf. I am aware that floating point variables cannot be accurate to 16sf, but I'm curious as to why the outputted value is 3.333333253860474. I presumed that maybe every digit after the 7th sf might just be junk stored in the memory location used by the variable. To check this, I copied the code used, compiled and ran it myself, andf got the exact same output. Therefore, I am not supposing that their is a reason for these, seeminly random, last 9 digits outputted. Can anyone explain why exactly std::cout << f; gives this output?

Upvotes: 2

Views: 178

Answers (2)

luk32
luk32

Reputation: 16070

Remember that you have a finite space to hold a number. So have to sample the continous space of real numbers. Imagine that you are working in decimal system instead of binary. And you have 10 digits. You can't represent 1.000000000001 exactly. So you have to round it.

Moreover the sampling does not have to have a fixed precision. E.g. how can you represent 3 000 000 000 000 in 10 digits? It's simple, you can use exponential notation it's 3*10^12. See only 5 digits! This is very close to how floating point works. Imagine you have 10 digits, let's fix our base to 10, so we don't waste digits on this. We are left with a*10^b. Changing the ratio of digits between a and b trades off the precision and range available. As an exercise I would suggest using 3/7 and 5/5 and try to represent few numbers using the exponential notation.

If you change the base to 2 you are practically there. The "junk" comes from using the powers of 2 instead powers of 10.

Usually float in c/c++ implements single precision value of IEEE 754 standard, although NathanOlivier is right to point out, that this is left to implementation.

To check how many digits are relevant, c++ offers std::numeric_limits. For the ideone system it's 6. The rest is not junk, it comes from the binary representation of the value. There are appropriate math formulas.

Here is a good explanation of math behind the single precision floating point representation of IEEE 754 standard. Floating point numbers are usually rounded to the nearest representable value. I think this is relevant if you are interested in floating point representation, in spite that technically it is not guaranteed to follow IEEE 754, most implementations across most compilers and languages do so.

You play around with below example (live):

#include <iostream>
#include <limits>
#include <cmath>
using namespace std;

int main() {
    cout << std::numeric_limits<float>::digits10 << '\n';
    cout << std::numeric_limits<float>::is_iec559 << '\n';
    cout.precision(20);
    cout << 3.333333333333333 << '\n';
    for(int i = 0; i < 10; ++i) {
        float f = i;
        cout << "f: " << f << " next:" <<  nextafter(f, f+1.0) << " diff: " << f-nextafter(f, f+1.0) << '\n';
    }
    return 0;
}

As you can see, only 6 signifiacnt digits are guaranteed for back and forth conversion between a float and corresponding base-10 string representation.

You can also observe that the intervals between the closest representable values are not fixed (hence floating point). They scale with the relative value of the number.

Upvotes: 1

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

I assume you were expecting to see 3.333333000000000 instead.

Numbers on computers aren't stored in decimal (base 10), and 3.333333000000000 can't be represented exactly in binary (base 2). The number 3.333333253860474 is the closest value1 which has all threes in the available significant figures.

Imagine if you had a number system which had only increments of 1.1:

|-------|-------|-------|-------|
0      1.1     2.2     3.3     4.4

In this system, if you wanted the number 3, you'd be out of luck, and might get 3.3 instead. If you didn't know off-hand that 1.1 was the smallest "increment" in that system, the .3 might seem "random".

It's a bit like that.

1 I don't know whether it's the closest value, or the closest value upwards. Doesn't really matter either way.

Upvotes: 7

Related Questions