0
a <- 10
b <- 10.02
paste(a-b)
#[1] "-0.0199999999999996"

library(Rmpfr)
mpfr(10.02, 100)
#1 'mpfr' number of precision  100   bits 
#[1] 1.001999999999999957367435854394e1

Note: similar question was posted elsewhere (Why are these numbers not equal?), but this question is slightly different due to the context it has: the problem is found when I perform paste() or str_c() function, so other users who search paste would be redirected to this post and find their answers. Besides, the comments contain interesting thoughts and answers, which are not seen in the previous post.

DanielY
  • 351
  • 1
  • 4
  • 9
  • What exactly is your definition of "as is" in this case? – NelsonGon Jan 30 '19 at 17:12
  • Is there a way for R to show paste(a-b) as -.02 ? Just like what we would normally think? 10 - 10.02 = -0.02 ?? – DanielY Jan 30 '19 at 17:20
  • 1
    It is presenting the floating point number 'as is'. That's what the actual result of the calculation is; if you do that math in Excel, and expand it to show 16 decimal places, you get the same answer. Unfortunately, that's just a reality of working with floating point arithmetic. If you want it to show -0.02, you'll need to round the results of the calculation to some number of decimal places. – Josh Eller Jan 30 '19 at 17:20
  • @JoshEller, oh wow. You were right! Excel does show the same thing when I made it show 16 decimal places. So that's how computer represents these numbers internally? What's the mechanism behind it? like it's reliably -0.019...96, rather than -0.019...97 or 98? why 96? :) – DanielY Jan 30 '19 at 17:26
  • 2
    Well, internally, numbers are stored in binary, so powers of 2. For example, `9` in decimal = `1*8+0*4+0*2+1*1`, or `1001` in binary. For fractions, you go in the opposite direction, 2^-1, 2^-2, etc. So, `3/8` in decimal = `0*1/2 + 1*1/4 + 1*1/8`, or `0.011`. Floating point numbers use that same format, but you'll notice that some numbers simply can't be represented exactly. For example, no matter how many powers of 2 you add together, you'll never be able to get exactly `1/3`. That's the issue; computers need to work with limited amounts of space, that real numbers might not fit into. – Josh Eller Jan 30 '19 at 17:31
  • 1
    The truth is that the floating point standard is what most of the world has settled on as 'good enough'. There are plenty of other systems out there with much higher accuracy, but there's always trade-offs, either in storage space or calculation time. Your idea would work fine for this case, but if you want to do a calculation using `π`, it wouldn't. You'd need to split your algorithm into two separate systems, one that works on numbers that can have a nice integer representation, and ones that don't, making calculations much tougher (what if I want to add a rational and irrational number?) – Josh Eller Jan 30 '19 at 17:44
  • @JoshEller: Brilliant! Glad to know the internal powers-of-2 mechanism. That gives me an idea how to resolve the issue. For example, we could just move all floating numbers to integer (as much as possible), do calculation, and move back to original decimal places. In my original question, we can do: paste((100*a-100*b)/100), which will give us exactly "-0.02" – DanielY Jan 30 '19 at 17:44
  • can we typically assume that in R, if we know ahead of the time, these numbers have up to two decimal places, then paste(round(a-b,2)) would always be accurate? – DanielY Jan 30 '19 at 17:47
  • 1
    In general, yes, you're never going to see floating point errors at any appreciable amount of decimal places. The thing to be careful of is if you're multiplying/dividing by very large or very small numbers, this sort of error can spiral into appreciable errors. For example, `round((10-10.02)*100000000000000,2) = -1999999999999.96`, which could be an error of 4 cents. – Josh Eller Jan 30 '19 at 17:54
  • Actually, I find that if I know the decimal places are going to be 2 at most, I can simply do the following in R, and the answer will always be accurate, since R uses 16 decimal places: paste(round(a-b, 10)), where 10 can also be any integer between 3 and 15 (inclusive) – DanielY Jan 30 '19 at 18:03

0 Answers0