Logic regarding summation of decimals [duplicate] - r

This question already has answers here:
Why are these numbers not equal?
(6 answers)
Closed 8 years ago.
Does the last statement in this series of statements make logical sense to anybody else? R seems to give similar results for a small subset of possible sums of decimals under 1. I cannot recall any basic mathematical principles that would make this true, but it seems to be unlikely to be an error.
> 0.4+0.6
[1] 1
> 0.4+0.6==1.0
[1] TRUE
> 0.3+0.6
[1] 0.9
> 0.3+0.6==0.9
[1] FALSE

Try typing 0.3+0.6-0.9, on my system the result is -1.110223e-16 this is because the computer doesn't actually sum them as decimal numbers, it stores binary approximations, and sums those. And none of those numbers can be exactly represented in binary, so there is a small amount of error present in the calculations, and apparently it's small enough not to matter in the first one, but not the second.

Floating point arithmetic is not exact, but the == operator is. Use all.equal to compare two floating point values in R.
isTRUE(all.equal(0.3+0.6, 0.9))
You can also define a tolerance when calling all.equals.
isTRUE(all.equal(0.3+0.6, 0.9, tolerance = 0.001))

Related

How to properly compare numbers in scientific notation using R? [duplicate]

This question already has answers here:
Why are these numbers not equal?
(6 answers)
Closed 1 year ago.
I was reading the following tutorial for testing proportions in two populations. After running
prop.test(x=c(342,290), n=c(400,400))
I received a p-value of 9.558674e-06, which the tutorial says is greater than the alpha level of .05. I assumed this was a typo, and was just comparing the p-value to its value in decimal notation, 0.000009558674, but received "False". I even turned off scientific notation using
options(scipen=999)
and when printing out the p-value from the object returned by prop.test, I still receive "False" when comparing the p-value to 0.000009558674 for equality, it recognizes the p-value as lesser than. Why is this the case?
You may want to consider using the all.equal() function. The tolerance between the values can be set with the tolerance argument.
isTRUE(all.equal(2, 2.00000001))
## [1] TRUE
isTRUE(all.equal(2, 2.00000001, tolerance = 0.0000000001))
## [1] FALSE

Round numbers in R correctly [duplicate]

This question already has answers here:
Round up from .5
(7 answers)
Closed 1 year ago.
There are a number of threads about this question. None seems to answer the simple question: why does R round incorrectly and how can I let it round correctly?
Correct rounding to the i-th decimal x considers the i+1-th decimal. If it is 5 or larger then x is is set to x+1. If it is 4 or smaller then x is returned. For example 1.45 is rounded to the first decimal as 1.5. 1.44 is rounded 1.4. However, in R
> round(1.45,1)
[1] 1.4
But
> round(1.46,1)
[1] 1.5
So it changes the convention to 'if the i+1th decimal is 6 or larger, then x is set to x+1'. Why? And how can I change this to the convention I am familiar with?
Most decimal fractions are not exactly representable in binary double precision
Learned here: https://stat.ethz.ch/R-manual/R-devel/library/base/html/Round.html
Section "Warnings":
Rounding to decimal digits in binary arithmetic is non-trivial (when digits != 0) and may be surprising. Be aware that most decimal fractions are not exactly representable in binary double precision. In R 4.0.0, the algorithm for round(x, d), for d > 0, has been improved to measure and round “to nearest even”, contrary to earlier versions of R (or also to sprintf() or format() based rounding).

0.5<0.5 returns TRUE in R? [duplicate]

This question already has answers here:
Why are these numbers not equal?
(6 answers)
Closed 2 years ago.
I came across a strange thing in R programming. When I simulate a sequence and want to judge whether the element is less than 0.5,
t=(1:1440)/1440
x=(t[720]-t[648])/0.1
x
#output:[1] 0.5
x<1/2
#output:[1] TRUE
x=0.5
x<1/2
#output:[1] FALSE
The two results are completely opposite and obviously the second result is what I want. Can anybody help me?
Floating point arithmetic is not exact in R, and the value you expect to be numerically exact to 0.5 may in fact be slightly more (or less). One possible workaround here would be to use rounding:
t <- (1:1440)/1440
x <- (t[720]-t[648]) / 0.1
round(x, 1) < 0.5

Why is this easy comparison false? [duplicate]

This question already has answers here:
Why are these numbers not equal?
(6 answers)
Closed 8 years ago.
Why does this simple statement evaluate to FALSE in R?
mean(c(7.18, 7.13)) == 7.155
Furthermore, what do I have to do in order to make this a TRUE statement? Thanks!
Floating point arithmetic is not exact. The answer to this question has more information.
You can actually see this:
> print(mean(c(7.18,7.13)), digits=16)
[1] 7.154999999999999
> print(7.155, digits=16)
[1] 7.155
In general, do not compare floating point numbers for equality (this applies to pretty much every programming language, not just R).
You can use all.equal to do an inexact comparison:
> all.equal(mean(c(7.18,7.13)), 7.155)
[1] TRUE
It's probably due to small rounding error. Rounding to the third decimal place shows that they are equal:
round(mean(c(7.18, 7.13)), 3) == 7.155
Generally, don't rely on numerical comparisons to give expected logical outputs :)

Why did I obtain wrong answer when using "=="? [duplicate]

This question already has answers here:
Why are these numbers not equal?
(6 answers)
Closed 9 years ago.
If I type:
x<-seq(0,20,.05)
x[30]
x[30]==1.45
Why do I obtain a False from the last line of code? What did I do wrong here?
This question has been asked a million times, albeit in different forms. This is due to floating point inaccuracy. Also here's another link on floating point errors you may want to catch up on!
Try this to first see what's going on:
x <- seq(0, 20, 0.5)
sprintf("%.20f", x[30]) # convert value to string with 20 decimal places
# [1] "14.50000000000000000000"
x[30] == 14.5
# [1] TRUE
All is well so far. Now, try this:
x <- seq(0, 20, 0.05)
sprintf("%.20f", x[30]) # convert value to string with 20 decimal places
# [1] "1.45000000000000017764"
x[30] == 1.45
# [1] FALSE
You can see that the machine is able to accurately represent this number only up to certain digits. Here, up to 15 digits or so. So, by directly comparing the results, you get of course a FALSE. Instead what you could do is to use all.equal which has a parameter for tolerance which equals .Machine$double.eps ^ 0.5. On my machine this evaluates to 1.490116e-08. This means if the absolute difference between the numbers x[30] and 1.45... is < this threshold, then all.equal evaluates this to TRUE.
all.equal(x[30], 1.45)
[1] TRUE
Another way of doing this is to explicitly check with a specific threshold (as #eddi's answer shows it).
This has to do with the fact that these are double's, and the correct way of comparing double's in any language is to do something like:
abs(x[30] - 1.45) < 1e-8 # or whatever precision you think is appropriate

Resources