I'd appreciate any idea on how to do it, so we can compare them with each other.
Here is one to start out with:
is.natural <- function(x)
{
x>0 && identical(round(x), x)
}
I'd appreciate any idea on how to do it, so we can compare them with each other.
Here is one to start out with:
is.natural <- function(x)
{
x>0 && identical(round(x), x)
}
The docs suggest a similar method, so I doubt you'll get any better. Remember to include an epsilon to take into account precision issues!
is.naturalnumber <-
function(x, tol = .Machine$double.eps^0.5) x > tol & abs(x - round(x)) < tol
is.naturalnumber(1) # is TRUE
(x <- seq(1,5, by=0.5) )
is.naturalnumber( x ) #--> TRUE FALSE TRUE ...
Be aware that identical()
checks for storage type as well: your is.natural(1L)
returns FALSE
since typeof(1L)
is integer
but typeof(round(1L))
is double
. As an alternative to marcog I suggest the following function which uses all.equal()
to do the checking and handles complex numbers:
is.natural <- function(x, tol = .Machine$double.eps^0.5) {
(abs(Im(x)) < tol) &&
(abs(Re(x)) > tol) &&
isTRUE(all.equal(x, round(x),
tolerance=tol,
check.attributes=FALSE,
check.names=FALSE))
}
One more solution is using a bit of arithmetics :
is.natural2 <- function(x,tol=.Machine$double.eps^0.5){
sign(x) - abs(x-round(x)) >= 1-tol
}
Now, when checking all solutions, it turned out that the one of Tal and the one of caracal didn't give the correct result:
is.natural <- function(x)
{
x>0 & identical(round(x), x)
}
is.natural2 <- function(x,tol=.Machine$double.eps^0.5){
sign(x) - abs(x-round(x)) >= 1-tol
}
is.natural3 <- function(x, dig=15){ x > 0 & zapsmall(x, dig) == round(x) }
is.natural4 <- function(x,tol=.Machine$double.eps^0.5){
x > 0 &
isTRUE(all.equal(x,round(x),
tolerance=tol,
check.attributes=FALSE,
check.names=FALSE))
}
is.naturalnumber <- function(x, tol = .Machine$double.eps^0.5){
x > 0 & abs(x - round(x)) < tol
}
Then :
> X <- (seq(0,3,by=0.5)^0.5)^2
> is.natural(X)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE # wrong
> is.natural2(X)
[1] FALSE FALSE TRUE FALSE TRUE FALSE TRUE
> is.natural3(X)
[1] FALSE FALSE TRUE FALSE TRUE FALSE TRUE
> is.natural4(X)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE # wrong
> is.naturalnumber(X)
[1] FALSE FALSE TRUE FALSE TRUE FALSE TRUE
Regarding the timing :
> X <- (seq(0,1000000,by=0.5)^0.5)^2
> system.time(is.natural2(X))
user system elapsed
0.24 0.03 0.26
> system.time(is.natural3(X))
user system elapsed
0.67 0.00 0.67
> system.time(is.naturalnumber(X))
user system elapsed
0.22 0.01 0.23
which makes marcog the winner.
You should always have integer size limit in mind: .Machine$integer.max
. Even if you do some kind of "check", if given numerical value exceeds the limit, R will see it as double
, and it is stored in a different manner.
> (x <- as.integer(.Machine$integer.max + 1))
[1] NA
Warning message:
NAs introduced by coercion
> (x <- as.double(.Machine$integer.max + 1))
[1] 2147483648
> typeof(x)
[1] "double"
> x <- 2147483647L
> typeof(x)
[1] "integer"
> x <- 2147483648L
Warning message:
non-integer value 2147483648 qualified with L; using numeric value
> typeof(x)
[1] "double"
You need two tests: greater than 0 and close enough to an integer. The identical() test fails too often because it also checks for extraneous attributes and storage mode. The zapsmall provides the ability to restrict rounding to a particular number of digits and does so in a manner that can be applied to vectors of candidate values. You can adjust the number of significant digits if desired.
is.natural <- function(x, dig=15){ x > 0 &
zapsmall(x, dig) == round(x) &
x < .Machine$integer.max }
x <- (2^0.5)^2
x ==2
# [1] FALSE (machine mathematics)
is.natural(x)
# [1] TRUE
Edit: A good point was made about checking for range, so that was added.