News for hackers. Stuff that matters.
Re:0.30000000000000004 by such_a_casual on Friday November 13, 2015 @09:59AM (#10560130)
edit: The OP has accepted my pull request and this explanation is now directly available on the website.

It's a shame that the web page doesn't explain why floating point numbers are inaccurate when it comes to decimals. It's actually pretty simple. When you have a base 10 system (like ours), it can only express fractions that use a prime factor of the base. The prime factors of 10 are 2 and 5. So 1/2, 1/4, 1/5, 1/8, and 1/10 can all be expressed cleanly because the denominators all use prime factors of 10. In contrast, 1/3, 1/6, and 1/7 are all repeating decimals because their denominators use a prime factor of 3 or 7.

In binary (or base 2), the only prime factor is 2. So you can only express fractions cleanly which only contain 2 as a prime factor. In binary, 1/2, 1/4, 1/8 would all be expressed cleanly as decimals. While, 1/5 or 1/10 would be repeating decimals.

So 0.1 and 0.2 (1/10 and 1/5) while clean decimals in a base 10 system, are repeating decimals in the base 2 system the computer is operating in. When you do math on these repeating decimals, you end up with leftovers which carry over when you convert the computer's base 2 (binary) number into a more human readable base 10 number.

Re:0.30000000000000004 by StefanKarpinski on Friday November 13, 2015 @11:48AM (#10560778)
Spot on. I would add to this explanation that the real confusion comes from the fact that in most languages when you write `0.1`, it doesn't mean 0.1 = 1/10 – instead it means the closest number to 0.1 of the form n/2^k where n < 2^53. Namely 0.1000000000000000055511151231257827021181583404541015625, which we can represent in decimal because 2 divides 10. And, of course, the illusion that `0.1` is actually 0.1 is supported by the great efforts [1] made to print floating-point values with the least number of digits necessary to reproduce them, so `0.1` still looks like 0.1 when you print it even though it isn't.

[1] http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/pr...

Re:0.30000000000000004 by fryguy on Friday November 13, 2015 @01:17PM (#10561356)
In decimal if you only have 5 digits for mantissa and you write 2/3, it becomes 0.66667 which is a little bit more than 2/3. Similarly, if you write the binary number 0.0000'0000'1 in decimal with 5 digits for mantissa, it becomes 0.0039063 instead of 0.00390625. If in some faraway land they use binary math, they would likely ask why such a simple binary number got rounded off.
Re:0.30000000000000004 by benten10 on Monday November 16, 2015 @08:22AM (#10574249)
Huhh, that was a totally unexpected encounter to Prof. Ramsey's page.
Re:0.30000000000000004 by iamphilrae on Friday November 13, 2015 @10:05AM (#10560169)
THANK YOU! That is one of the best explanations on that matter I have seen. I've never considered why floating points are inaccurate, I just took it for a given (which I hate doing). Now I understand why, and so my own wisdom has increased ever so slightly. Today is a good day.
Re:0.30000000000000004 by acqq on Friday November 13, 2015 @10:26AM (#10560300)
See also:

http://cs.furman.edu/digitaldomain/more/ch6/dec_frac_to_bin....

".1 (decimal) = .00011001100110011 . . . (base 2)"

Notice the repeating pattern? The exact number must have infinite number of binary digits. Wherever you cut (whichever fixed number of bits you want to keep) you lose something.

Re:0.30000000000000004 by Raphmedia on Friday November 13, 2015 @01:11PM (#10561312)
To live in a world where information is not only accessible, but where you can also contribute to it easily is truly amazing. I use Git daily for source control, but I am always amazed when I see it used to manage content in an open source way.
Re:0.30000000000000004 by such_a_casual on Friday November 13, 2015 @01:33PM (#10561463)
Completely agree. I would love to see more content creators using things like github to allow others to contribute and improve content.
Re:0.30000000000000004 by Nemi on Friday November 13, 2015 @11:28AM (#10560653)
So, this is a great explanation. I have never heard it expressed this way and I love it.

However, I am a little confused. In your first paragraph you say that 10's prime factors are 5 and 2, so 1/10 can be expressed cleanly. In paragraph two you say that binary only has a prime factor of 2, but 10 is divisible by 2, so why doesn't 1/10 express cleanly in binary?

Re:0.30000000000000004 by such_a_casual on Friday November 13, 2015 @11:34AM (#10560695)
In the fraction 1/10, the denominator is 10. The prime factors of 10 are 2 and 5.

Binary does not contain the prime factor of 5 necessary to represent 1/10 cleanly as a decimal. It only contains the 2.

Similarly, the prime factors for 1/6 would be 3 and 2. In a base 10 number system, you only have the 2. So you end up with a repeating decimal (0.1666666).

Re:0.30000000000000004 by aeorgnoieang on Friday November 13, 2015 @11:33AM (#10560685)
A fraction can only be expressed 'cleanly' if its denominator uses only the prime factors of the base.
Re:0.30000000000000004 by btilly on Friday November 13, 2015 @02:16PM (#10561815)
For example, 30 is divisible by 10, but 1/30 is not represented cleanly in base 10.
Re:0.30000000000000004 by reuven on Saturday November 14, 2015 @10:56AM (#10566034)
I have been teaching programming for years, and love to point out that floating-point arithmetic isn't accurate. Many experienced programmers are shocked to discover the problems with floats.

But I never before had a good answer for which numbers would be accurate, and which wouldn't. This explanation was crystal clear and helpful. Thanks for providing it.

Re:0.30000000000000004 by david_ar on Friday November 13, 2015 @09:03PM (#10564022)
Obligatory pedantic comment: "base-2 decimal" is an oxymoron

https://en.wikipedia.org/wiki/Repeating_decimal#Extension_to...

Re:0.30000000000000004 by raiph on Saturday November 14, 2015 @03:04AM (#10564911)
> 0.1 and 0.2 ... are repeating decimals ...

Au contraire, `0.1` and `0.2` are non-repeating decimals.

Their approximations may be repeating of course, and some languages indulge in such approximations, but there's nothing intrinsic about `0.1` that requires that it be approximated prior to storage rather than stored with 100% accuracy.

Many lisps do what it takes to store rationals as rationals, maintaining 100% accuracy. Perl 6 likewise treats literals of the form `1/10` or `0.1` as the rationals they are, again maintaining 100% accuracy.

Re:0.30000000000000004 by jayceekay on Friday November 13, 2015 @12:29PM (#10561036)
> In contrast, 1/3, 1/6, and 1/7 are all repeating decimals because their denominators use a prime factor of 3 or 7.

doesn't 1/6 use a prime factor of 2 as well?

Re:0.30000000000000004 by such_a_casual on Friday November 13, 2015 @12:59PM (#10561242)
In the fraction 1/6, the prime factors of the denominator are 2 and 3. A base 10 number system has the 2 but not the 3.
Re:0.30000000000000004 by jayceekay on Saturday November 14, 2015 @07:06PM (#10567866)
got it, thanks!
Re:0.30000000000000004 by thedufer on Friday November 13, 2015 @12:46PM (#10561154)
Yes, but in order to have a non-repeating decimal expansion, the denominator must share _all_ of its factors with the base. That is, only fractions that, when reduced, have a denominator of the form 2^n*5^m (for natural numbers n, m) will terminate in base 10. The explanation given could probably be clearer.
Re:0.30000000000000004 by jayceekay on Saturday November 14, 2015 @07:06PM (#10567864)
ah yes, the _all_ is what i missed. thanks.