Why can't decimal numbers be represented exactly in binary?

There have been several questions posted to SO about floating-point representation. For example, the decimal number 0.1 doesn't have an exact binary representation, so it's dangerous to use the == operator to compare it to another floating-point number. I understand the principles behind floating-point representation.

What I don't understand is why, from a mathematical perspective, are the numbers to the right of the decimal point any more "special" that the ones to the left?

For example, the number 61.0 has an exact binary representation because the integral portion of any number is always exact. But the number 6.10 is not exact. All I did was move the decimal one place and suddenly I've gone from Exactopia to Inexactville. Mathematically, there should be no intrinsic difference between the two numbers -- they're just numbers.

By contrast, if I move the decimal one place in the other direction to produce the number 610, I'm still in Exactopia. I can keep going in that direction (6100, 610000000, 610000000000000) and they're still exact, exact, exact. But as soon as the decimal crosses some threshold, the numbers are no longer exact.

What's going on?

Edit: to clarify, I want to stay away from discussion about industry-standard representations, such as IEEE, and stick with what I believe is the mathematically "pure" way. In base 10, the positional values are:

... 1000  100   10    1   1/10  1/100 ...

In binary, they would be:

... 8    4    2    1    1/2  1/4  1/8 ...

There are also no arbitrary limits placed on these numbers. The positions increase indefinitely to the left and to the right.


Decimal numbers can be represented exactly, if you have enough space - just not by floating binary point numbers. If you use a floating decimal point type (eg System.Decimal in .NET) then plenty of values which can't be represented exactly in binary floating point can be exactly represented.

Let's look at it another way - in base 10 which you're likely to be comfortable with, you can't express 1/3 exactly. It's 0.3333333... (recurring). The reason you can't represent 0.1 as a binary floating point number is for exactly the same reason. You can represent 3, and 9, and 27 exactly - but not 1/3, 1/9 or 1/27.

The problem is that 3 is a prime number which isn't a factor of 10. That's not an issue when you want to multiply a number by 3: you can always multiply by an integer without running into problems. But when you divide by a number which is prime and isn't a factor of your base, you can run into trouble (and will do so if you try to divide 1 by that number).

Although 0.1 is usually used as the simplest example of an exact decimal number which can't be represented exactly in binary floating point, arguably 0.2 is a simpler example as it's 1/5 - and 5 is the prime that causes problems between decimal and binary.


Side note to deal with the problem of finite representations:

Some floating decimal point types have a fixed size like System.Decimal others like java.math.BigDecimal are "arbitrarily large" - but they'll hit a limit at some point, whether it's system memory or the theoretical maximum size of an array. This is an entirely separate point to the main one of this answer, however. Even if you had a genuinely arbitrarily large number of bits to play with, you still couldn't represent decimal 0.1 exactly in a floating binary point representation. Compare that with the other way round: given an arbitrary number of decimal digits, you can exactly represent any number which is exactly representable as a floating binary point.


The reason for the imprecision is the nature of number bases. In base 10, you can't exactly represent 1/3. It becomes 0.333... However, in base 3, 1/3 is exactly represented by 0.1 and 1/2 is an infinitely repeating decimal (tresimal?). The values that can be finitely represented depend on the number of unique prime factors of the base, so base 30 [2 * 3 * 5] can represent more fractions than base 2 or base 10. Even more for base 210 [2 * 3 * 5 * 7].

This is a separate issue from the "floating point error". The inaccuracy there is because a few billion values are spread across a much greater range. So if you have 23 bits for the significand, you can only represent about 8.3 million distinct values. Then an 8-bit exponent provides 256 options for distributing those values. This scheme allows the most precise decimals to occur near 0, so you can almost represent 0.1.


For example, the number 61.0 has an exact binary representation because the integral portion of any number is always exact. But the number 6.10 is not exact. All I did was move the decimal one place and suddenly I've gone from Exactopia to Inexactville. Mathematically, there should be no intrinsic difference between the two numbers -- they're just numbers .

Let's step away for a moment from the particulars of bases 10 and 2. Let's ask - in base b , what numbers have terminating representations, and what numbers don't? A moment's thought tells us that a number x has a terminating b -representation if and only if there exists an integer n such that xb^n is an integer.

So, for example, x = 11/500 has a terminating 10-representation, because we can pick n = 3 and then xb^n = 22 , an integer. However x = 1/3 does not, because whatever n we pick we will not be able to get rid of the 3.

This second example prompts us to think about factors, and we can see that for any rational x = p/q (assumed to be in lowest terms), we can answer the question by comparing the prime factorisations of b and q . If q has any prime factors not in the prime factorisation of b , we will never be able to find a suitable n to get rid of these factors.

Thus for base 10, any p/q where q has prime factors other than 2 or 5 will not have a terminating representation.

So now going back to bases 10 and 2, we see that any rational with a terminating 10-representation will be of the form p/q exactly when q has only 2 s and 5 s in its prime factorisation; and that same number will have a terminating 2-representatiion exactly when q has only 2 s in its prime factorisation.

But one of these cases is a subset of the other! Whenever

q has only 2 s in its prime factorisation

it obviously is also true that

q has only 2 s and 5 s in its prime factorisation

or, put another way, whenever p/q has a terminating 2-representation, p/q has a terminating 10-representation . The converse however does not hold - whenever q has a 5 in its prime factorisation, it will have a terminating 10-representation , but not a terminating 2-representation. This is the 0.1 example mentioned by other answers.

So there we have the answer to your question - because the prime factors of 2 are a subset of the prime factors of 10, all 2-terminating numbers are 10-terminating numbers, but not vice versa. It's not about 61 versus 6.1 - it's about 10 versus 2.

As a closing note, if by some quirk people used (say) base 17 but our computers used base 5, your intuition would never have been led astray by this - there would be no (non-zero, non-integer) numbers which terminated in both cases!

链接地址: http://www.djcxy.com/p/77460.html

上一篇: JavaScript显示浮点数到2个小数位

下一篇: 为什么十进制数不能完全用二进制表示?