views:

303

answers:

9
+1  Q: 

Rounding Errors?

In my course, I am told:

Continuous values are represented approximately in a memory, and therefore computing with floats involves rounding errors. These are tiny discrepancies in bit patterns; thus the test e==f is unsafe if e and f are floats.

Referring to Java.

Is this true? I've used comparison statements with doubles and floats and have never had rounding issues. Never have I read in a textbook something similar. Surely the virtual machine accounts for this?

+3  A: 

This is always true. There are some numbers which cannot be represented accurately using float point representation. Consider, for example, pi. How would you represent a number which has infinite digits, within a finite storage? Therefore, when comparing numbers you should check if the difference between them is smaller then some epsilon. Also, there are several classes which exist that can help you achieve greater accuracy such as BigDecimal and BigInteger.

laginimaineb
+1 for BigDecimal
dfa
yes, but if two calculations yield the same floating point number, using e==f would return true?
Beau Martínez
@Beau, if e and f are really the same number, the check returns true. But there are some caveats, e.g a seemingly simple and mathematically true comparison like ((x * y) / y == x) can be false
Ben Schwehn
You have succeeded in representing pi exactly in finite storage: by using its name. There's more to numbers than their customary decimal representation. Consider 1/3: This also has infinite digits (in base 10) but can be represented exactly: as a rational number (or in base 3). even though it can't be represented exactly as a base 2 or 10 floating point number.
Adrian Pronk
A: 

yes, Java also uses floating point arithmetic.

dfa
+11  A: 

This applies to Java just as much as to any other language using floating point. It's inherent in the design of the representation of floating point values in hardware.

More info on floating point values:

What Every Computer Scientist Should Know About Floating-Point Arithmetic

Ben Schwehn
+1 - a terrific reference.
duffymo
One point: If two calculations are exactly the same, then their resulting values will also be the same. The problem arises when two calculations are mathematically equivalent but different.
dfrankow
+2  A: 

Yes, as other answers have said. I want to add that I recommend you this article about floating point accuracy: Visualizing floats

Artur Soler
+1  A: 

Yes, representing 0.1 exactly in base-2 is the same as trying to represent 1/3 exactly in base 10.

duffymo
+5  A: 

It is true.

It is an inherent limitation of how floating point values are represented in memory in a finite number of bits.

This program, for instance, prints "false":

public class Main {
  public static void main(String[] args) {
    double a = 0.7;
    double b = 0.9;
    double x = a + 0.1;
    double y = b - 0.1;
    System.out.println(x == y);
  }
}

Instead of exact comparison with '==' you usually decide on some level of precision and ask if the numbers are "close enough":

System.out.println(Math.abs(x - y) < 0.0001);
Christian Vest Hansen
Good explanation. Your last code sample should probably use Math.abs(x - y) instead of x - y, though.
markusk
You're right. Corrected.
Christian Vest Hansen
Because of the intuitive code example, this is my answer of choice. Nice one!
Beau Martínez
+1  A: 

It is right. Note that Java has nothing to do with it, the problem is inherent in floating point math in ANY language.

You can often get away with it with classroom-level problems but it's not going to work in the real world. Sometimes it won't work in the classroom.

An incident from long ago back in school. The teacher of an intro class assigned a final exam problem that was proving a real doozy for many of the better students--it wasn't working and they didn't know why. (I saw this as a lab assistant, I wasn't in the class.) Finally some started asking me for help and some probing revealed the problem: They had never been taught about the inherent inaccuracy of floating point math.

Now, there were two basic approaches to this problem, a brute force one (which by chance worked in this case as it made the same errors every time) and a more elegant one (which would make different errors and not work.) Anyone who tried the elegant approach would hit a brick wall without having any idea why. I helped a bunch of them and stuck in a comment explaining why and to contact me if he had questions.

Of course next semester I hear from him about this and I basically floored the entire department with a simple little program:

10 X = 3000000
20 X = X + 1
30 If X < X + 1 goto 20
40 Print "X = X + 1"

Despite what every teacher in the department thought, this WILL terminate. The 3 million seed is simply to make it terminate faster. (If you don't know basic: There are no gimmicks here, just exhausting the precision of floating point numbers.)

Loren Pechtel
+1  A: 

Of course it is true. Think about it. Any number must be represented in binary.

Picture: "1000" as 0.5or 1/2, that is, 2 ** -1. Then "0100" is 0.25 or 1/4. You can see where I'm going.

How many numbers can you represent in this manner? 2**4. Adding more bits duplicates the available space, but it is never infinite. 1/3 or 1/10, for the matter 1/n, any number not multiple of 2 cannot be really represented.

1/3 could be "0101" (0.3125) or "0110" (0.375). Either value if you multiply it by 3, will not be 1. Of course you could add special rules. Say you "when you add 3 times '0101', make it 1"... this approach won't work in the long run. You can catch some but then how about 1/6 times 2?

It's not a problem of binary representation, any finite representation has numbers that you cannot represent, they are infinite after all.

eipipuz
+1  A: 

Most CPUs (and computer languages) use IEEE 754 floating point arithmetic. Using this notation, there are decimal numbers that have no exact representation in this notation, e.g. 0.1. So if you divide 1 by 10 you won't get an exact result. When performing several calculations in a row, the errors sum up. Try the following example in python:

>>> 0.1
0.10000000000000001
>>> 0.1 / 7 * 10 * 7 == 1
False

That's not really what you'd expect mathematically.

By the way: A common misunderstanding concerning floating point numbers is, that the results are not precise and cannot be comapared safely. This is only true if you really use fractions of numbers. If all your math is in the integer domain, doubles and floats do exactly the same as ints and also can be compared safely. They can be safely used as loop counters, for example.

Nikolai Ruhe
I disagree with your comments about float in the integer domain. Simple example 1: float f2 = 20000000; if (f2 == ++f2) { ;//oops }Example 2: its entirely unobvious when this loop will terminate: float f = 0; while (true) { if (f == ++f) { break; } }
Ben Schwehn
They can be safely compared so long as you remain in the range where they can be represented as integers. See my message for an example of where this fails.
Loren Pechtel
@Ben: Staying in range is an issue with ints too:int i = 0; while (i < 2147483648) {}But I agree that there are more subtle problems with overflowing floats.
Nikolai Ruhe