6

Possible Duplicate:
Why are these numbers not equal?

The below expression, which evaluates to 0.1, is considered larger than 0.1.

> round(1740/600,0) - 1740/600
[1] 0.1
> (round(1740/600,0) - 1740/600) <= 0.1
[1] FALSE //???!!???
> (round(1740/600,0) - 1740/600) <= 0.1000000000000000000000000000000000000001
[1] TRUE

Thinking that the issue might be due to rounding I tried this with the same result:

> 3 - 2.9
[1] 0.1
> (3 - 2.9) <=0.1
[1] FALSE

So, what gives and how do I fix it without fudging the cutoff?

Community
  • 1
  • 1
dnagirl
  • 20,196
  • 13
  • 80
  • 123

2 Answers2

16

There are R functions that automatically take sensible approaches to the "equality problem":

> (3 - 2.9) <=0.1
#[1] FALSE

> all.equal( (3 - 2.9) , 0.1)
#[1] TRUE

It uses the sqrt of R's smallest positive floating point number as its default threshold, so it handles multiplications and division propagated errors. Ends up being around 1e-08

IRTFM
  • 258,963
  • 21
  • 364
  • 487
14

From the Floating-Point Guide:

Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?

Because internally, computers use a format (binary floating-point) that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.

When the code is compiled or interpreted, your “0.1” is already rounded to the nearest number in that format, which results in a small rounding error even before the calculation happens.

What can I do to avoid this problem?

That depends on what kind of calculations you’re doing.

  • If you really need your results to add up exactly, especially when you work with money: use a special decimal datatype.
  • If you just don’t want to see all those extra decimal places: simply format your result rounded to a fixed number of decimal places when displaying it.
  • If you have no decimal datatype available, an alternative is to work with integers, e.g. do money calculations entirely in cents. But this is more work and has some drawbacks.
IRTFM
  • 258,963
  • 21
  • 364
  • 487
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • so if I need to do exact comparisons, I should move the decimal to the right and truncate so that I'm comparing integers? – dnagirl Jul 29 '11 at 15:04
  • 1
    @dnagirl: either that or compare using an epsilon value (see link for more details). But in any case, abandon the idea of having an "exact comparison" when you're dealing with inexact data. The real question is where your data is coming from - if your input is already approximate, then worrying about artificial corner cases like this is pretty pointless. – Michael Borgwardt Jul 29 '11 at 15:12
  • In this case I'm trying to subset timecourse data by the proximity in time of a measurement to a periodic set of events. My data is measured once per second. The events occur at 10 minutes intervals. I want to get the 60 seconds on either side of each event. – dnagirl Jul 29 '11 at 15:22
  • 1
    See `all.equal` for testing if two numbers are (nearly) equal. – Aaron left Stack Overflow Jul 29 '11 at 16:46
  • @dnagirl: so you're comparing second-granularity timestamps? In that case, working purely with integers would be the easiest solution. – Michael Borgwardt Jul 29 '11 at 17:36
  • Decimal types don't solve floating-point inaccuracy problems; they just make the errors the same as you'd get by calculating it yourself. This makes them very well suited for handing money (since the goal is to get the same answer as hand calculation), but they won't eliminate error in other applications. (In a decimal data type, how do you define 1/3 so that 1/3 + 1/3 + 1/3 == 1?) – David Thornley Jul 29 '11 at 17:51
  • @David: you're right in that the point of decimal types is to eliminate differences to the decimal arithmetic we're used to, but some of those differences are rounding errors that simply don't occur with decimal types. – Michael Borgwardt Jul 29 '11 at 18:00
  • I'd like to down vote this answer.. I reviewed the page linked and it discusses the topic of floating point equality problems only, which are symptoms rather than root causes. The real issue here is R has no native support for arbitrary precision arithmetic, which is what the Question is asking for (without yet knowing that is the goal). I have tried using Rmpfr but it is easily missed in favor of R native options (that lead to floating point problems with accuracy). I preferred Python2 because it handles arbitrary precision arithmetic natively, now it is dead both py3 and R cannot solve it – Stof May 06 '20 at 02:09