Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Counter intuitive testing for whole numbers: 63 = (45 x 1.4) = 62

Tags:

r

I wrote a (potentially not particularly good!) function to test if a number is a whole number or not:

is.wholeNumber <- function(x) x == floor(x)

In general this function works fine for my purpose as I am really only considering cases where I'm testing numbers with a handful of deciminal places, so my naive understanding was that machine precision shouldn't be a factor.

When I apply this function in the case 45 x 1.4 = 63, however I get

> is.wholeNumber( 45 * 1.4)
[1] FALSE

This appears to occur because the floor function of R is not evaluating as I would expect:

> floor(45 * 1.4)
[1] 62

which should in fact be 63.


On doing some reading I came across this popular post about how to code this in R. The top voted answer there suggests the function

is.wholeNumber <- function(x) ( x %% 1 ) == 0

which again does not appear to work in my context, since I get

> (45 * 1.4 ) %% 1
[1] 1

The second most upvoted post suggests using

is.wholeNumber <- function(x) all.equal(x, as.integer(x))

and whilst once again this does not work, it does give the illuminatingly unexpected output of

> is.wholeNumber( 45 * 1.4)
[1] "Mean relative difference: 0.01587302"

I have now tried this in both a clean R studio workspace, and from R terminal (R 3.4.2 Short Summer) and duplicated this issue. I'd be interested to know:

  1. Can people reproduce this issue on their machines?
  2. Why I am getting this counter intuitive result?
  3. What is a correct way to work around this?
like image 838
owen88 Avatar asked Apr 03 '18 18:04

owen88


1 Answers

Following function will give you correct results:

is.wholeNumber <- function(x, tol = .Machine$double.eps^0.5)  abs(x - round(x)) < tol
like image 75
sfr Avatar answered Oct 29 '22 22:10

sfr