Search code examples
pythonprecisionnumeric

Accurate evaluation of function for negative x


Is there a way to accurately evaluate f(x) as given below for moderate negative x (around -1e6 to -1e2), while sticking with float64 numbers?

def f(x):
    return 0.5 + arctan(x/sqrt(3)) / pi + sqrt(3)*x/(pi*(x*x+3))

For example:

g(-10_000) == 1.1026577511479050e-12  # actual closest float64 (what I want)
f(-10_000) == 1.1026461116240595e-12  # current implementation
#                   ^^^^^^^^^^^^ <- wrong

Solution

  • I ended up with this:

    def g(x):
        # approximation to f(x)
        # method: For x<0 we have the identity: atan(x) === -pi/2 - atan(1/x)
        # substitute this into f(x) then expand about -infinity, simplify & truncate
        assert x <= -100
        k = 3**0.5 / (pi * x)
        y = -3.0/(x*x)
        return k*y*(2/3 + y*(4/5 + y*(6/7 + y*(8/9 + y*10/11))))
    

    This keeps the relative error below ~3e-16 for the range I'm interested in and has about the same performance, or even a little faster:

    x rel_err(f) rel_err(g) abs_err(f) abs_err(g)
    -100 -2.012e-11 -2.774e-16 -2.217e-17 -3.058e-22
    -1,000 -5.660e-08 -4.603e-18 -6.241e-17 -5.076e-27
    -10,000 -1.056e-05 -1.571e-16 -1.164e-17 -1.733e-28
    -100,000 -6.418e-02 -2.529e-17 -7.077e-17 -2.789e-32
    -1,000,000 -4.585e+01 -9.824e-17 -5.056e-17 -1.083e-34