1

If the size of a float is 4 bytes then shouldn't it be able to hold digits from 8,388,607 to -8,388,608 or somewhere around there because I probably calculated it wrong.

Why does f display the extra 15 because the value of f (0.1) is still between 8,388,607 to -8,388,608 right?

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        float f = .1;
        printf("%lu", sizeof(float));
        printf("%.10f", f);
    }
    return 0;
}

2012-08-28 20:53:38.537 prog[841:403] 4
2012-08-28 20:53:38.539 prog[841:403] 0.1000000015
Mysticial
  • 464,885
  • 45
  • 335
  • 332
stumped
  • 3,235
  • 7
  • 43
  • 76
  • possible duplicate of [Why does a C floating-point type modify the actual input of 125.1 to 125.099998 on output?](http://stackoverflow.com/questions/6532502/why-does-a-c-floating-point-type-modify-the-actual-input-of-125-1-to-125-099998) – Daniel Fischer Aug 29 '12 at 01:12
  • 1
    Not so sure this _is_ a dupe, though it's certainly related. This one has the added complication of misunderstanding the representation, over and above the standard "why is 0.1 not 0.1?". – paxdiablo Aug 29 '12 at 01:37
  • I would suggest you find the [IEEE Floating Point Standard](http://en.wikipedia.org/wiki/IEEE_floating_point) document on the web and study it. (Or, if it's too arcane, find somewhere where it's summarized.) It's unreasonable to ask someone to describe the standard here -- it would be a small book. – Hot Licks Aug 29 '12 at 02:02

1 Answers1

2

The values -8,388,608 ... 8,388,607 lead me to believe that you think floats use two's complement, which they don't. In any case, the range you have indicates 24 bits, not the 32 that you'd get from four bytes.

Floats in C use IEEE754 representation, which basically has three parts:

  • the sign.
  • the exponent (sort of a scale).
  • the fraction (actual digits of the number).

You basically get a certain amount of precision (such as 7 decimal digits) and the exponent dictates whether you use those for a number like 0.000000001234567 or 123456700000.

The reason you get those extra digits at the end of your 0.1 is because that number cannot be represented exactly in IEEE754. See this answer for a treatise explaining why that is the case.

Numbers are only representable exactly if they can be built by adding inverse powers of two (like 1/2, 1/16, 1/65536 and so on) within the number of bits of precision (ie, number of bits in the fraction), subject to scaling.

So, for example, a number like 0.5 is okay since it's 1/2. Similarly 0.8125 is okay since that can be built from 1/2, 1/4 and 1/16.

There is no way (at least within 23 bits of precision) that you can build 0.1 from inverse powers of two, so it gives you the nearest match.

Community
  • 1
  • 1
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Always helpful to note the pragmatist's solution to our most popular floating point domain (currency): work in cents instead of dollars (i.e. multiply all input by 100 before storing it (as an int), and do all your math this way. Then divide by 100 (into a doube/float) as you present the output. – Chris Trahey Aug 29 '12 at 01:38
  • Sorry, I think I misinterpreted this excerpt: "And this is essentially how they are stored: a 32-bit floating number has 8 bits dedicated to holding the exponent (a signed integer) and 23 bits dedicated to holding the mantissa with the remaining 1 bit used to hold the sign." Do the 8 bits that are dedicated to holding the exponent have to be positive in order for those bits to be used for holding the exponent? – stumped Aug 29 '12 at 01:54
  • @stumped: no, it doesn't have to be positive. There are certain values of the exponent which are used to represent special numbers like NaN or +/- infinity. If the exponent is not one of those values, it behaves a little like two's complement, representing a number from (for example) -127 to 127. This would result in a scaling by 2 raised to that number (2^-40, 2^99 and so so). – paxdiablo Aug 29 '12 at 02:05