views:

4170

answers:

18

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.

+134  A: 

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 (e.g. 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.

Jon Skeet
That's a damn fine example sir!
Tom Ritter
...wish I could upvote this twice. I've been asked about this entirely too many times. It's almost like people can't think outside of base 10. hehe
Justin Niessner
Humanity is screwed by having more than 2 fingers in total.
Jon Skeet
http://en.wikipedia.org/wiki/Coprime
Alex B
Yeah, there are 10 kinds of people in the world - those who understand binary and those who don't.
duffymo
@Alex: Yes, I probably want to edit that and remove "coprime" there: it's not quite enough.
Jon Skeet
http://en.wikipedia.org/wiki/IEEE_754-1985 provides a decent explanation of the internal representation of IEEE binary floating point numbers. And it's examples may help clarify why precision is affected by representational choice.
LBushkin
"Decimal numbers _can_ be represented exactly". false. if at best misleading. you still have finite space/time, and most numbers cannot be represented in _any_ form anyway.
nlucaroni
So it's the relative-primeness of the two bases that causes the problem, correct? By that line of reasoning, would it be correct to say that any number that can be represented exactly in base 10 can also be represented exactly in, say, base 20 because they share the same prime factors?
Barry Brown
@Barry: Yes, that's right. And any binary number can be represented exactly in decimal for exactly the same reason.
Jon Skeet
@nlucaroni: Note that I said "decimal number" not "any number". If it can be represented in decimal, then it's clearly a rational number to start with. I'll edit for the finiteness side of things.
Jon Skeet
I don't understand what you're saying (if anything) about the difference between base 10 and base 2. Any finite number (rational and/or irrational) can be expressed exactly (definingly 'exactly' as meaning 'with vanishingly small imprecision') if you can have a non-finite number of decimal places, no matter whether in base 2 or in base 10.
ChrisW
@ChrisW: That's because of the way you're defining "exactly". My point is that however many "3"s you have at the end of 0.333333... you won't get to 1/3... whereas if you give me any exact binary number of the form [10100010101].[101010101] for as big as you want on each side of the binary point, I can give you a decimal value which is absolutely exactly the same value, in a finite number of digits.
Jon Skeet
I do, however, take your point that a truly infinite number of 3s (rather than just an *arbitrary but finite* number) would give an infinitely good approximation of 1/3. Will edit.
Jon Skeet
@JonSkeet: *Ctrl+Alt+Delete* would look awkward with just two fingers.
Lars Haugseth
@Barry: not relative prime, but with one base having a prime factor that is not a factor of the other base (e.g. 10 and 6 are not relatively prime, but 1/10 is an infinite decimal in base 6, and 1/6 is an infinite decimal in base 10).
Jason S
We just have to wait until evolution gives us either 2 hands with 8 vingers each or 4 hands with 4 fingers each. I just don't like the chop 8 off idea.
Gamecat
It's worth noting that .3333333 repeating infinitely, is not an approximation of 1/3 but is in fact equal to 1/3. It's the exact same concept as .999999... is equal to 1.
Jacob Schlather
.999999999999999 even with an infinite number of digits is definitely not equal to one. It asymptotically approaches 1, but never reaches it. It's the exact same concept as 1/x != 0 even as x->infinity.
muusbolla
@muusbolla: I believe this depends on various precise definitions, particularly "equals". For example, it makes sense to suggest that if there is no non-zero value of d for which x + d = y, then x=y. You can't find any such value of d for the difference between 0.9 recurring and 1...
Jon Skeet
We can represent 1/3, 1/9, 1/27, or any rational in decimal notation. We do it by adding an extra symbol. For example, a line over the digits that repeat in the decimal expansion of the number. So what we need to do is represent numbers as a sequence of binary numbers, a radix point, and some other symbol to indicate the repeating part of the sequence.
ntownsend
@muusbolla: No. The numbers represented by the decimal representation `1` and the decimal representation `0.9...` (infinitely repeating `9`s after the decimal point) are equal. Perhaps the easiest way to see this is the following: Let x = `0.9...`. Note that `10x = 9.9....`. Therefore `9x = 10x - x = 9.9... - 0.9... = 9` so that `9x = 9` and `x = 1`. There are other ways to see this, but I believe that this is the simplest.
Jason
@Lars Haugseth: think Ctrl+Alt *pedals* :o)
Piskvor
@Piskvor: This is why the term nose boot was invented.
Joe D
+3  A: 

If you make a big enough number with floating point (as it can do exponents), then you'll end up with inexactness in front of the decimal point, too. So I don't think your question is entirely valid because the premise is wrong; it's not the case that shifting by 10 will always create more precision, because at some point the floating point number will have to use exponents to represent the largeness of the number and will lose some precision that way as well.

Daniel Lew
+3  A: 

BCD - Binary-coded Decimal - representations are exact. They are not very space-efficient, but that's a trade-off you have to make for accuracy in this case.

Alan
BCD are no more or less exact than any other base. Example: how do you represent 1/3 exactly in BCD? You can't.
Jörg W Mittag
BCD is an exact representation of a DECIMAL, thus the, um, "decimal" part of its name. There is no exact decimal representation of 1/3 either.
Alan
A: 
Dima
+6  A: 

The root (mathematical) reason is that when you are dealing with integers, they are countably infinite.

Which means, even though there are an infinite amount of them, we could "count out" all of the items in the sequence, without skipping any. That means if we want to get the item in the 610000000000000th position in the list, we can figure it out via a formula.

However, real numbers are uncountably infinite. You can't say "give me the real number at position 610000000000000" and get back an answer. The reason is because, even between 0 and 1, there are an infinite number of values, when you are considering floating-point values. The same holds true for any two floating point numbers.

More info:

http://en.wikipedia.org/wiki/Countable_set

http://en.wikipedia.org/wiki/Uncountable_set

Update: My apologies, I appear to have misinterpreted the question. My response is about why we cannot represent every real value, I hadn't realized that floating point was automatically classified as rational.

TM
Actually, rational numbers *are* countably infinite. But not every *real* number is a rational number. I can certainly produce a sequence of exact decimal numbers which will reach any exact decimal number you want to give me eventually. It's if you need to deal with *irrational* numbers as well that you get into uncountably infinite sets.
Jon Skeet
True, I should be saying "real", not "floating-point". Will clarify.
TM
At which point the logic becomes less applicable, IMO - because not only can we not deal with all *real* numbers using binary floating point, but we can't even deal with all *rational* numbers (such as 0.1). In other words, I don't think it's really to do with countability at all :)
Jon Skeet
@jonskeet I know that disagreeing with Jon Skeet would break a fundamental law of nature, so of course I won't do it :) However, I do think that it is okay to think of the internal representation of the numbers as indices to a set of the values that you want to represent externally. With this line of thinking, you can see that no matter how big your list of indices is (even if you had say, infinite bits of precision), you *still* wouldn't be able to represent all the real numbers.
TM
Floating point numbers are, by definition, rational.
molf
@TM: But the OP isn't trying to represent all the real numbers. He's trying to represent all exact *decimal* numbers, which is a subset of the *rational* numbers, and therefore only countably infinite. If he were using an infinite set of bits *as a decimal floating point type* then he'd be fine. It's using those bits as a *binary* floating point type that causes problems with decimal numbers.
Jon Skeet
@molf that's a really good point. I guess I was misinterpreting the question as "why can't we represent any fractional value when we can represent any integer value".
TM
+7  A: 

You might find this helpful to understand exactly what's going on inside a floating point nubmber: Anatomy of a floating point number.

John D. Cook
A: 

The number 61.0 does indeed have an exact floating-point operation—but that's not true for all integers. If you wrote a loop that added one to both a double-precision floating point number and a 64-bit integer, eventually you'd reach a point where the 64-bit integer perfectly represents a number, but the floating point doesn't—because there aren't enough significant bits.

It's just much easier to reach the point of approximation on the right side of the decimal point. If you started writing out all the numbers in binary floating point, it'd make more sense.

Another way of thinking about it is that when you note that 61.0 is perfectly representable in base 10, and shifting the decimal point around doesn't change that, you're performing multiplication by powers of ten (10^1, 10^-1). In floating point, multiplying by powers of two does not affect the precision of the number. Try taking 61.0 and dividing it by three repeatedly for an illustration of how a perfectly precise number can lose its precise representation.

John Calsbeek
+4  A: 

It's the same reason you cannot represent 1/3 exactly in base 10, you need to say 0.33333(3). In binary it is the same type of problem but just occurs for different set of numbers.

James
+9  A: 

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.

James M.
It's not at all unrelated to floating point representation. The base you choose for your floating point defines which numbers can be exactly represented. Yes, fixed-size floating point numbers will always have limits to their accuracy - but it's the base that stops many *decimal* numbers being exactly representable in *binary* floating point, not the size. Take as many bits as you want - you still won't be able to represent decimal 0.1 in binary exactly.
Jon Skeet
Correct, I updated it to hopefully clarify that the second paragraph is referring to errors caused by a separate issue.
James M.
Right - yup, that's a lot better :)
Jon Skeet
A: 

There are an infinite number of rational numbers, and a finite number of bits with which to represent them. See http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems.

zpasternack
But even with an infinite number of bits, if you used a floating *binary* point, you still wouldn't be able to represent 0.1 exactly, just like you can't represent 1/3 exactly in decimal even with an infinite number of bits.
Jon Skeet
@Jon That's untrue: with an *infinite* number of decimals, I *can* for example express 'one third' *exactly*. The real-world problem is that *not physically possible* to have "an infinite number" of decimals or of bits.
ChrisW
+1  A: 

There's a threshold because the meaning of the digit has gone from integer to non-integer. To represent 61, you have 6*10^1 + 1*10^0; 10^1 and 10^0 are both integers. 6.1 is 6*10^0 + 1*10^-1, but 10^-1 is 1/10, which is definitely not an integer. That's how you end up in Inexactville.

Mark Ransom
+1  A: 

A parallel can be made of fractions and whole numbers. Some fractions eg 1/7 cannot be represented in decimal form without lots and lots of decimals. Because floating point is binary based the special cases change but the same sort of accuracy problems present themselves.

mP
A: 

you know integer numbers right? each bit represent 2^n


2^4=16
2^3=8
2^2=4
2^1=2
2^0=1

well its the same for floating point(with some distinctions) but the bits represent 2^-n 2^-1=1/2=0.5
2^-2=1/(2*2)=0.25
2^-3=0.125
2^-4=0.0625

Floating point binary representation:

sign  Exponent    Fraction(i think invisible 1 is appended to the fraction )
B11  B10 B9 B8   B7 B6 B5 B4 B3 B2 B1 B0

yan bellavance
+5  A: 

(Note: I'll append 'b' to indicate binary numbers here. All other numbers are given in decimal)

One way to think about things is in terms of something like scientific notation. We're used to seeing numbers expressed in scientific notation like, 6.022141 * 10^23. Floating point numbers are stored internally using a similar format - mantissa and exponent, but using powers of two instead of ten.

Your 61.0 could be rewritten as 1.90625 * 2^5, or 1.11101b * 2^101b with the mantissa and exponents. To multiply that by ten and (move the decimal point), we can do:

(1.90625 * 2^5) * (1.25 * 2^3) = (2.3828125 * 2^8) = (1.19140625 * 2^9)

or in with the mantissa and exponents in binary:

(1.11101b * 2^101b) * (1.01b * 2^11b) = (10.0110001b * 2^1000b) = (1.00110001b * 2^1001b)

Note what we did there to multiply the numbers. We multiplied the mantissas and added the exponents. Then, since the mantissa ended greater than two, we normalized the result by bumping the exponent. It's just like when we adjust the exponent after doing an operation on numbers in decimal scientific notation. In each case, the values that we worked with had a finite representation in binary, and so the values output by the basic multiplication and addition operations also produced values with a finite representation.

Now, consider how we'd divide 61 by 10. We'd start by dividing the mantissas, 1.90625 and 1.25. In decimal, this gives 1.525, a nice short number. But what is this if we convert it to binary? We'll do it the usual way -- subtracting out the largest power of two whenever possible, just like converting integer decimals to binary, but we'll use negative powers of two:

1.525         - 1*2^0   --> 1
0.525         - 1*2^-1  --> 1
0.025         - 0*2^-2  --> 0
0.025         - 0*2^-3  --> 0
0.025         - 0*2^-4  --> 0
0.025         - 0*2^-5  --> 0
0.025         - 1*2^-6  --> 1
0.009375      - 1*2^-7  --> 1
0.0015625     - 0*2^-8  --> 0
0.0015625     - 0*2^-9  --> 0
0.0015625     - 1*2^-10 --> 1
0.0005859375  - 1*2^-11 --> 1
0.00009765625...

Uh oh. Now we're in trouble. It turns out that 1.90625 / 1.25 = 1.525, is a repeating fraction when expressed in binary: 1.11101b / 1.01b = 1.10000110011...b Our machines only have so many bits to hold that mantissa and so they'll just round the fraction and assume zeroes beyond a certain point. The error you see when you divide 61 by 10 is the difference between:

1.100001100110011001100110011001100110011...b * 2^10b
and, say:
1.100001100110011001100110b * 2^10b

It's this rounding of the mantissa that leads to the loss of precision that we associate with floating point values. Even when the mantissa can be expressed exactly (e.g., when just adding two numbers), we can still get numeric loss if the mantissa needs too many digits to fit after normalizing the exponent.

We actually do this sort of thing all the time when we round decimal numbers to a manageable size and just give the first few digits of it. Because we express the result in decimal it feels natural. But if we rounded a decimal and then converted it to a different base, it'd look just as ugly as the decimals we get due to floating point rounding.

Boojum
+2  A: 

This is a good question.

All your question is based on "how do we represent a number?"

ALL the numbers can be represented with decimal representation or with binary (2's complement) representation. All of them !!

BUT some (most of them) require infinite number of elements ("0" or "1" for the binary position, or "0", "1" to "9" for the decimal representation).

Like 1/3 in decimal representation (1/3 = 0.3333333... <- with an infinite number of "3")

Like 0.1 in binary ( 0.1 = 0.00011001100110011.... <- with an infinite number of "0011")

Everything is in that concept. Since your computer can only consider finite set of digits (decimal or binary), only some numbers can be exactly represented in your computer...

And as said Jon, 3 is a prime number which isn't a factor of 10, so 1/3 cannot be represented with a finite number of elements in base 10.

Even with arithmetic with arbitrary precision, the numbering position system in base 2 is not able to fully describe 6.1, although it can represent 61.

For 6.1, we must use another representation (like decimal representation, or IEEE 854 that allows base 2 or base 10 for the representation of floating-point values)

ThibThib
You could represent 1/3 as the fraction itself. You don't need an infinite amount of bits to represent it. You just represent it as the fraction 1/3, instead of the result of taking 1 and dividing it by 3. Several systems works that way. You then need a way to use the standard / * + - and similar operators to work on the representation of fractions, but that's pretty easy - you can do those operations with a pen and paper, teaching a computer to do it is no big deal.
nos
I was talking about "binary (2's complement) representation". Because, of course, using an other representation may help you to represent *some* number with finite number of elements (and you will need infinite number of elements for some others)
ThibThib
+1  A: 

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 x b^n is an integer.

So, for example, x = 11/500 has a terminating 10-representation, because we can pick n = 3 and then x b^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 2s and 5s in its prime factorisation; and that same number will have a terminating 2-representatiion exactly when q has only 2s in its prime factorisation.

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

q has only 2s in its prime factorisation

it obviously is also true that

q has only 2s and 5s 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!

AakashM
A: 

The high scoring answer above nailed it.

First you were mixing base 2 and base 10 in your question, then when you put a number on the right side that is not divisible into the base you get problems. Like 1/3 in decimal because 3 doesnt go into a power of 10 or 1/5 in binary which doesnt go into a power of 2.

Another comment though NEVER use equal with floating point numbers, period. Even if it is an exact representation there are some numbers in some floating point systems that can be accurately represented in more than one way (IEEE is bad about this, it is a horrible floating point spec to start with, so expect headaches). No different here 1/3 is not EQUAL to the number on your calculator 0.3333333, no matter how many 3's there are to the right of the decimal point. It is or can be close enough but is not equal. so you would expect something like 2*1/3 to not equal 2/3 depending on the rounding. Never use equal with floating point.

dwelch
+3  A: 

To repeat what I said in my comment to Mr. Skeet: we can represent 1/3, 1/9, 1/27, or any rational in decimal notation. We do it by adding an extra symbol. For example, a line over the digits that repeat in the decimal expansion of the number. What we need to represent decimal numbers as a sequence of binary numbers are 1) a sequence of binary numbers, 2) a radix point, and 3) some other symbol to indicate the repeating part of the sequence.

Hehner's quote notation is a way of doing this. He uses a quote symbol to represent the repeating part of the sequence. The article: http://www.cs.toronto.edu/~hehner/ratno.pdf and the Wikipedia entry: http://en.wikipedia.org/wiki/Quote_notation.

There's nothing that says we can't add a symbol to our representation system, so we can represent decimal rationals exactly using binary quote notation, and vice versa.

ntownsend
That notation system works if we know where the cycle starts and ends. Humans are pretty good at detecting cycles. But, in general, computers aren't. To use be able to use a repetition symbol effectively, the computer would have to be able to figure out where the cycles are after doing a calculation. For the number 1/3, for example, the cycle starts right away. But for the number 1/97, the cycle doesn't show itself until you've worked out the answer to at least 96 digits. (Actually, you'd need 96*2+1 = 193 digits to be sure.)
Barry Brown
Actually it's not hard at all for the computer to detect the cycle. If you read Hehner's paper he describes how to detect the cycles for the various arithmetic operations.For example, in the division algorithm, which uses repeated subtraction, you know where the cycle begins when you see a difference that you have seen before.
ntownsend
Also, the question was about representing numbers exactly. Sometimes exact representation means a lot of bits. The beauty of quote notation is that Hehner demonstrates that on average there is a 31% saving in the size of representation compared to the standard 32-bit fixed-length representation.
ntownsend