Click here to Skip to main content
15,867,771 members
Articles / Programming Languages / C#
Tip/Trick

Natural Logarithms and Exponent

Rate me:
Please Sign up or sign in to vote.
4.93/5 (7 votes)
9 Jan 2012CPOL4 min read 47.3K   7   7
Algorithms for Logarithms and Powers
Recently I've been working on writing my own Math library in C#. It's not meant to be a serious improvement on anything that already exists, but is more of a learning experience for me. I'm sure that every programmer after using library functions for a while begins to wonder "hey, how does that function work!?" Well, I did, and this is part of the result.

So far I've implemented most of the functions, but the other day I got to Logarithms and Exponentiation.
Ouch.

The Logarithm weren't that bad. I had come up with a recursive algorithm about 2 years ago that would solve the Logarithm for any base. It wasn't the fastest function in the world, but it was simple, and easy to use, and I'm proud I came up with it myself. Here it is for anyone who's interested.

C#
    public static double Log(double Power, double Base)
{
    double Whole, N, Sign;
    Sign = 1.0;

    #region Error Checking
    if (Power <= 1.0 || Base <= 1.0)
    {
        if (Power <= 0.0 || Base <= 0.0 )
        {
            return double.NaN;
        }
        if (Power < 1.0)
        {
            Power = 1.0 / Power;
            Sign *= -1.0;
        }
        if (Base < 1.0)
        {
            Sign *= -1.0;
            Base = 1.0 / Base;
        }
        if (Power == 1.0)
        {
            if (Base != 1.0)
            {
                return 0.0;
            }
            return 1.0;
        }
    }
    #endregion

    Whole = Power;
    N = 0.0;

    while (Whole >= Base)
    {
        Whole /= Base;
        N++;
    }
    if (Whole == 1.0)
    {
        return (Sign * N);
    }
    return Sign * (N + (1.0 / Log(Base, Whole)));
}


Like I said, it's pretty easy to use. It can be used to solve for any base, whether it be E, 2, 10, etc. But as I said, it's not the fastest, and it is a little memory intensive compared to other functions. I had read that there was a Taylor series that could be used to find the Natural Logarithm of a number, but when I implemented it, it was painfully slow, and in many cases just flat out didn't work.

During my research though I had discovered that there was a Taylor Series for finding the Power of E (e^x)[^].

C#
public static double Exp(double Exponent)
{
    double X, P, Frac, I, L;
    X = Exponent;
    Frac = X;
    P = (1.0 + X);
    I = 1.0;

    do
    {
        I++;
        Frac *= (X / I);
        L = P;
        P += Frac;
    }while(L != P);

    return P;
}


Sweet, simple, and to the point. That's how a function should be.

But after several hours of looking, I could not find hide nor hair of an algorithm for the Natural Logarithm...

Then it hit me.
(stupid function; won't watch where it's going)

Several years ago I read about an algorithm by a mathematician named John Gabriel, which he came up with to find the Nth Root of a number. (Unfortunately his website seems to be gone, but they have a copy of his algorithm here[^]).

C#
public static double NthRoot(double Power, double Rt)
{
    /* (C) John Gabriel */
    double A, N, S, T, L, R;
    A = Power;
    N = Rt;
    S = 1.0;

    do
    {
        T = S;
        L = (A / Math.Pow(S, (N - 1.0)));
        R = (N - 1.0) *  S;
        S = (L + R) / N;
    }while(L != S);

    return S;
}


For one thing, I hadn't come up with a Pow function yet, so I did't want to implement this in my library yet.

But,

What if we already knew the Root, which is E, and we had a sweet and simple function that could raise E to any power, (which I just might happen to have lying around) if I then solved for N instead, would it give me the Natural Logarithm of the number?

You guessed it.

C#
public static double Ln(double Power)
{
    double N, P, L, R, A, E;
    E = 2.71828182845905;
    P = Power;
    N = 0.0;

            // This speeds up the convergence by calculating the integral
    while(P >= E)
    {
        P /= E;
        N++;
    }
            N += (P / E);
    P = Power;

    do
    {
        A = N;
        L = (P / (Exp(N - 1.0)));
        R = ((N - 1.0) * E);
        N = ((L + R) / E);
    }while(N != A);

    return N;
}


If you wanted to use it to solve the logarithm of any other number you would do this.

C#
public static double Log(double N, double B)
{
    return (Ln(N) / Ln(B));

    /*
     * To find the Log of Base 2, use
     * return (Ln(N) / 0.69314718055995);
     *
     * For the Log of Base 10, use
     * return (Ln(N) / 2.30258509299405);
             *
             * And make sure you get rid of the 'double B' Parameter
     */
}


And what's even nicer is that once you have a function for the Logarithm as well as the Exponentiation of E, you could use them together for several other functions.

If for instance we wanted to find the AntiLog (Find B in [B ^ E = P]) we would use this.

C#
public static double ALog(double Power, double Exponent)
{
    double T = Ln(Power);
    T /= Exponent;
    return Exp(T);
}


And even more useful, if we wanted to make a Pow function, we do this.

C#
public static double Pow(double Base, double Power)
{
    return Exp(Power * Ln(Base));
}


Ahhh, the joy and pain that comes with Logarithms and Exponents.

Well I hope you've all enjoyed this little journey with me. I'm very proud that I was able to get these functions working. These are some of the most basic algorithms that we use everyday, and I hope you all get a kick out of seeing what goes on backstage.

Before I end this I would like to say two things.

1) Please don't use these and expect to get the same sort of speed and efficiency you would in the System.Math Library. Those functions have been crafted for speed and precision, so don't expect these to match them. As I said at the start, they're not meant to be an improvement, just a learning tool.

2) Please be careful when using these, I haven't added any Error Checking, so it is possible this will throw an ArithmeticException(). Please also be especially careful when comparing floating point numbers. I edited them slightly from what I actually have in order to make them easier on the eyes. One way to do this would be to put a Counter variable in the Loops to make them stop at a certain number, somewhere between 25 and 30 should do.

Again, I hope you've all enjoyed this and learned something from it.

Take Care,
Jacob

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCan I Use This with GPL Code? Pin
linuxrocks12328-May-17 13:48
linuxrocks12328-May-17 13:48 
QuestionThanks! but... Pin
Member 1134697415-Jan-15 13:37
Member 1134697415-Jan-15 13:37 
GeneralMy vote of 5 Pin
hkapur9710-Oct-12 23:32
hkapur9710-Oct-12 23:32 
GeneralReason for my vote of 5 The best kind of programming - you d... Pin
Leo5616-Jan-12 20:57
Leo5616-Jan-12 20:57 
GeneralRe: Completely agree :) Thanks for the 5! Pin
Jacob F. W.18-Jan-12 18:38
Jacob F. W.18-Jan-12 18:38 
General"I could not find hide nor hair of an algorithm for the Natu... Pin
John Brett10-Jan-12 3:28
John Brett10-Jan-12 3:28 
GeneralRe: The problem with the Taylor Series is that they converge mus... Pin
Jacob F. W.11-Jan-12 8:58
Jacob F. W.11-Jan-12 8:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.