Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding overflow in log(cosh(x))

My simulation needs to implement

np.log(np.cosh(x))

This overflows for large x, i. e. I'm getting the RuntimeWarning: overflow encountered in cosh warning. In principle, as logarithm decreases the number in question, in some range of x, cosh should overflow while log(cosh()) should not.

Is there any solution for that in NumPy, for example similar in spirit to the np.log1p() function?

To provide more info: I am aware that a possible solution might be symbolic using SymPy https://github.com/sympy/sympy/issues/12671 however the simulation should be fast, and symbolic calculation AFAIK might slow it down significantly.

like image 383
WojciechR Avatar asked Sep 04 '19 09:09

WojciechR


1 Answers

The following implementation of log(cosh(x)) should be numerically stable:

import numpy as np

def logcosh(x):
    # s always has real part >= 0
    s = np.sign(x) * x
    p = np.exp(-2 * s)
    return s + np.log1p(p) - np.log(2)

Explanation:

For real values you could use the following identity:

log(cosh(x)) = logaddexp(x, -x) - log(2)
             = abs(x) + log1p(exp(-2 * abs(x))) - log(2)

which is numerically stable because the argument to exp is always non-positive. For complex numbers we instead require that the argument to exp has non-positive real part, which we achieve by using -x when real(x) > 0 and x otherwise.

like image 118
myrtlecat Avatar answered Oct 20 '22 08:10

myrtlecat