0

I'm running into odd behaviour with the asin() function in R. I have an expression that occasionally evaluates to -1 that I pass to asin(). Sometimes asin() responds with the expected value asin(-1) = 1.57.... other times it responds with NaNs produced.

The code below gives an example (from a larger function that computes growing degree days for insects):

 # works
 tempMax <- 22.6
 tempMin <- 10.0
 threshold <- 10

 meanT     <- (tempMax + tempMin) / 2

 amplitude <- (tempMax - tempMin) /2

 thetaSub <- ( (threshold - meanT)/amplitude )

 thetaOut  <- asin( thetaSub)

 # fails
tempMax <- 22.7
tempMin <- 10.0
threshold <- 10

meanT     <- (tempMax + tempMin) / 2

amplitude <- (tempMax - tempMin) /2

thetaSub <- ( (threshold - meanT)/amplitude )

thetaOut  <- asin( thetaSub)

Note that in both examples thetaSub evaluates to -1, but asin only 'works' in the first example.

Testing the function it seems that I get NaNs when tempMin == threshold and the integer value of tempMax is even and the decimal portion is .7 (e.g., 22.7, 24.7, 26.7).

I suspect that's not the reason, but just other cases that elict the same error. I'm guessing it's something to do with how the value of thetaSub is interpreted by asin, but I can't figure out why it works sometimes and not others.

edit.

@James has identified my problem as a floating point issue. How do I force the asin to 'ignore' the decimal places?

Chris
  • 418
  • 3
  • 10

1 Answers1

7

It's a floating point issue. The way floating point numbers work is that all numbers need to be mapped to the nearest one which can be expressed as a finite sum of powers of two and this may lead to small inaccuracies in the expected output and can be dependent upon how the numbers are calculated.

print(thetaSub,digits=22)
[1] -1.000000000000000222045

You should modify your code to use asin(max(-1,min(1,thetaSub))) to protect against this issue. If you are doing calculations in a vectorised way use pmax and pmin instead.

James
  • 65,548
  • 14
  • 155
  • 193