runderflow

R - Incorrect calculations for small values


I consider the following function: -x*exp(-x) - (1+exp(-x))*log(1+exp(-x))

It is a continuous function, but while plotting it in R I get a weird discontinuous graph over x from -38 to -34 (which is not really so low as to reach Inf/-Inf in the calculations). For example, the output for x=-37.36 and x=-37.38 is 0, but for x=-37.37 is -128. What could be the reason for this?

I am probably making some very basic error, but any help would be great. I have added the code and the plot.

Thanks!

x=seq(from=-38,to=-34,by=0.01)
kappa = -x*exp(-x) - (1+exp(-x))*log(1+exp(-x))

plot(x,kappa)

plot


Solution

  • Your formula suffers from a phenomenon due to the precision of floating point numbers. When you add small values to large numbers there is always the risk of precision loss.

    x <- seq(from=-38, to=-0, by=1)
    v1 <- exp(-x)
    v2 <- 1 + v1
    # The difference between `v1` and `v2` should be 1, however:
    v1 - v2
    #>  [1]  0  0 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
    #> [26] -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
    

    One simple solution would be using a package that provides floating point with higher precision like the Rmpfr package (see e.g. here). Another would be to find an alternate form that avoids +1 and exp(-x) + exp(x).

    It is important to note, that this is not flaw in R but a general issue of floating point arithmetic.

    Created on 2021-03-10 by the reprex package (v1.0.0)