views:

355

answers:

7
+1  Q: 

Arithmetic in ruby

Why this code 7.30 - 7.20 in ruby returns 0.0999999999999996, not 0.10?

But if i'll write 7.30 - 7.16, for example, everything will be ok, i'll get 0.14.

What the problem, and how can i solve it?

+1  A: 

That is a common error from how float point numbers are represented in memory.

Use BigDecimal if you need exact results.

result=BigDecimal.new("7.3")-BigDecimal("7.2")
puts "%2.2f" % result
Jonas Elfström
There is a pretty good discussion about this on: http://whynotwiki.com/Ruby_/_Numbers
Michael Sepcot
Note that BigDecimal only yields exact results if the number has a finite number of digits in base 10.
sepp2k
A: 

Floating point precision problem.

Martijn Courteaux
Your response is a label not an answer. What is supposed to happen next? Presumably the questioner Googles your response. I suppose that's one way to answer the question, but it sort of defeats the purpose of this site. You may find the question boring, the answer obvious, etc., but if so maybe let someone else answer it.
Telemachus
+3  A: 

The problem is that floating point is inaccurate. You can solve it by using Rational, BigDecimal or just plain integers (for example if you want to store money you can store the number of cents as an int instead of the number of dollars as a float).

BigDecimal can accurately store any number that has a finite number of digits in base 10 and rounds numbers that don't (so three thirds aren't one whole).

Rational can accurately store any rational number and can't store irrational numbers at all.

sepp2k
A: 

Since you are doing floating point math then the number returned is what your computer uses for precision.

If you want a closer answer, to a set precision, just multiple the float by that (such as by 100), convert it to an int, do the math, then divide.

There are other solutions, but I find this to be the simplest since rounding always seems a bit iffy to me.

This has been asked before here, you may want to look for some of the answers given before, such as this one: http://stackoverflow.com/questions/590822/dealing-with-accuracy-problems-in-floating-point-numbers

James Black
+10  A: 

What Every Computer Scientist Should Know About Floating-Point Arithmetic

pierr
Right. This is true regardless of language - Java, Ruby, C# all "suffer" from this. It's due to the choice of binary logic and our way of representing floating point numbers.
duffymo
+2  A: 

The problem is that some numbers we can easily write in decimal don't have an exact representation in the particular floating point format implemented by current hardware. A casual way of stating this is that all the integers do, but not all of the fractions, because we normally store the fraction with a 2**e exponent. So, you have 3 choices:

  1. Round off appropriately. The unrounded result is always really really close, so a rounded result is invariably "perfect". This is what Javascript does and lots of people don't even realize that JS does everything in floating point.

  2. Use fixed point arithmetic. Ruby actually makes this really easy; it's one of the only languages that seamlessly shifts to Class Bignum from Fixnum as numbers get bigger.

  3. Use a class that is designed to solve this problem, like BigDecimal

To look at the problem in more detail, we can try to represent your "7.3" in binary. The 7 part is easy, 111, but how do we do .3? 111.1 is 7.5, too big, 111.01 is 7.25, getting closer. Turns out, 111.010011 is the "next closest smaller number", 7.296875, and when we try to fill in the missing .003125 eventually we find out that it's just 111.010011001100110011... forever, not representable in our chosen encoding in a finite bit string.

DigitalRoss
+1  A: 

It is interesting to note that a number that has few decimals in one base may typically have a very large number of decimals in another. For instance, it takes an infinite number of decimals to express 1/3 (=0.3333...) in the base 10, but only one decimal in the base 3. Similarly, it takes many decimals to express the number 1/10 (=0.1) in the base 2.

ragnarius