pythonmathlogarithmapproximation

Approximating logarithm using harmonic mean


Here is a function to approximate log10(x+1) for (x+1) < ~1.2:

a = 1.097
b = 0.085
c = 2.31

ans = 1 / (a - b*x + c/x)

It should look like that:

equation of approximation

It works by adjusting harmonic mean to match log10, but the problem is in values of a, b, c.

The question is how to get just right a, b and c and how to make better approximation.

I made this code that can give a pretty good approximation for a, b, c, but my code wasn't able to make it any better.

import numpy as np

a = 1
b = 0.01
c = 2

def mlg(t):
    x = t
    if t == 0:
        x = 0.00000001
    x2 = x*x
    o = a - (b * x) + (c / x)
    return 1/o

def mlg0(t):
    x = t
    if t == 0:
        x = 0.00000001
    x2 = x*x
    o = a - (b * x) + (c / x)
    return o

for i in range(9000):
    n1 = np.random.uniform(0,1.19,1000)
    for i in range(1000):
        n = n1[i]
        o = np.log10(n+1)
        u = mlg(n) - o
        e = u ** 2

        de_da = 0 - 2 * (u) / (mlg0(n) ** 2)
        de_db = de_da * n 
        de_dc = de_da / n

        a -= de_da * 0.00001
        b -= de_db * 0.00001
        c -= de_dc * 0.00001

print(a,b,c)

How could the code be changed to generate better values?

I've used a method alike back propagation in NN, but it could not give me values any better.

Here is how the error is calculated:

equation of error calculation


Solution

  • Here are two approaches.

    Method 1: series expansion in x (better for negative and positive x)

    Method 2: fit the curve that passes through 3 points (here, x=0, ½ and 1)

    Method 1.

    If you expand them by Taylor series as powers of x then

    enter image description here

    Equating coefficients of x, x^2 and x^3 gives

    enter image description here

    In code:

    import math
    import numpy as np
    import matplotlib.pyplot as plt
    
    c = math.log( 10 )
    a = c / 2
    b = c / 12
    
    print( "a, b, c = ", a, b, c )
    
    
    x = np.linspace( -0.2, 0.2, 50 )
    y = np.log10( 1 + x )
    fit = x / ( a * x - b * x ** 2 + c )
    
    plt.plot( x, y  , 'b-', label="Original" )
    plt.plot( x, fit, 'ro', label="Fit"      )
    plt.legend()
    plt.show()
    

    Output:

    a, b, c =  1.151292546497023 0.19188209108283716 2.302585092994046
    

    enter image description here

    Method 2.

    Fit to three points. Here we require

    enter image description here

    If we require this to fit at x=0, ½ and 1 we get (including L’Hopital’s rule for the limit at x=0)

    enter image description here

    This time I have used your interval x in [0,1] to plot the fit

    import math
    import numpy as np
    import matplotlib.pyplot as plt
    
    c = math.log( 10 )
    a = c * ( 2/math.log(1.5) - 1/math.log(2) - 3 )
    b = 2 * c * ( 1/math.log(1.5) - 1/math.log(2) - 1 )
    
    print( "a, b, c = ", a, b, c )
    
    
    x = np.linspace( 0.0, 1.0, 50 )
    y = np.log10( 1 + x )
    fit = x / ( a * x - b * x ** 2 + c )
    
    plt.plot( x, y  , 'b-', label="Original" )
    plt.plot( x, fit, 'ro', label="Fit"      )
    plt.legend()
    plt.show()
    

    Output:

    a, b, c =  1.1280638006656465 0.1087207987723298 2.302585092994046
    

    enter image description here