[R] The elegant way to test if a number is a whole number

Marc Schwartz marc_schwartz at me.com
Thu Sep 8 22:41:26 CEST 2011


On Sep 8, 2011, at 3:09 PM, David Winsemius wrote:

> 
> On Sep 8, 2011, at 3:54 PM, Marc Schwartz wrote:
> 
>> 
>> On Sep 8, 2011, at 2:42 PM, David Winsemius wrote:
>> 
>>> 
>>> On Sep 8, 2011, at 3:35 PM, Alexander Engelhardt wrote:
>>> 
>>>> Am 08.09.2011 20:48, schrieb Marc Schwartz:
>>>>> There was a post from Martin Maechler some years ago and I had to search a bit to find it. For these sorts of issues, I typically trust his judgement.
>>>>> 
>>>>> The post is here:
>>>>> 
>>>>>  https://stat.ethz.ch/pipermail/r-help/2003-April/032471.html
>>>>> 
>>>>> His solution also handles complex numbers.
>>>> 
>>>> For those too lazy to follow
>>>> He is basically creating the function is.whole:
>>>> 
>>>> is.whole <- function(x)
>>>>   is.numeric(x) && floor(x)==x
>>> 
>>> Are you sure? I thought the test would have been all.equal(x, round(x,0) )
>>> 
>>> My reasoning was that 1.999999999999 should be considered 2 but floor would make it 1.
>> 
>> David, I am confuzzled. Why would that be equal to 2?
> 
> So that sqrt(3) * sqrt(3) would be a "whole number". (It is true the the floor based wholeness criterion would make sqrt(2)*sqrt(2)
> 
> Somehow it doesn't see "right" that only half of square roots of integers that have been squared should pass the wholeness test:
> 
> > is.whole <- function(a, tol = 1e-7) {
> +    is.eq <- function(x,y) {
> + 	 r <- all.equal(x,y, tol=tol)
> + 	 is.logical(r) && r
> +    }
> +    (is.numeric(a) && is.eq(a, floor(a))) ||
> +    (is.complex(a) && {ri <- c(Re(a),Im(a)); is.eq(ri, floor(ri))})
> + }
> > is.whole( sqrt(2)^2 )
> [1] TRUE
> > is.whole( sqrt(3)^2  )
> [1] FALSE
> 

<snip content>

OK. I suspect it may down to what assumptions one is willing to make, including the level of tolerance used for the comparison.

is.whole() of course works for 2 because:

> print(sqrt(2) ^ 2, 20)
[1] 2.0000000000000004441

is slightly larger than 2, so:

> floor(sqrt(2) ^ 2)
[1] 2

works, as does:

> round(sqrt(2) ^ 2, 0)
[1] 2


On the other hand:

> print(sqrt(3) ^ 2, 20)
[1] 2.9999999999999995559

is slightly smaller than 3, so:

> floor(sqrt(3) ^ 2)
[1] 2

versus:

> round(sqrt(3) ^ 2, 0)
[1] 3


Not sure if Martin (cc'd now) might have any comments 8 plus years later relative to this issue, as I would again defer to his judgement here.

The other solution proposed, using modulo division, would logically fail in both cases:

> (sqrt(3) ^ 2) %% 1 == 0
[1] FALSE

> (sqrt(2) ^ 2) %% 1 == 0
[1] FALSE


Regards,

Marc



More information about the R-help mailing list