3

I am working with annuities and have the following methods in my code:

public static double NumPMTsRemaining( double CurBalance, double ContractRate, double Pmt)
{
    double rt = PeriodicRate(ContractRate);
    return -1 * Math.Log(1 - (CurBalance * (rt) / Pmt)) / Math.Log(1 + (rt));
}

public static double MonthlyPMT(double OrigBalance, double ContractRate, int Term)
{
    double rt = PeriodicRate(ContractRate);
    if (ContractRate > 0)
        return (OrigBalance * rt * Math.Pow(1 + rt, Term)) / (Math.Pow(1 + rt, Term) - 1);
    else return OrigBalance / Term;
}

I use the former method to determine if the payment for a loan will insure the loans pays off in its life remaining. I use the latter method to determine if a payment is quoted for a payment period other than monthly and then replace it with a monthly payment if so. Upon reflection I can use the latter method for both tasks.

With that in mind, I was wondering if anyone knew off the top of their head if Math.Pow is faster/more efficient than/relative to Math.Log?
I assume that Math.Pow is the better choice, but would appreciate a bit of input.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
StephenWinburn
  • 107
  • 1
  • 9
  • 3
    Why don't you profile each method with say 100,000 calls and see for yourself which one is faster? – Jon Aug 13 '14 at 19:52
  • 1
    I'd expect `log` with a fixed base to be faster than `pow`, since pow is usually implemented by calling `log` on the base followed by a fixed base exponentiation function. If you benchmark, benchmark separately for x64 and x86 since the generated floating point code on those platforms is pretty different. – CodesInChaos Aug 13 '14 at 20:13
  • 3
    Unless this is a bottleneck of your application, use the easier to read version, not the faster version. – CodesInChaos Aug 13 '14 at 20:15
  • 2
    I note that `Term` is an integer. There are generally much faster methods than Math.Pow for integer powers see for example http://mindprod.com/jgloss/power.html. Only go this route if this is a performance bottleneck. – Salix alba Aug 13 '14 at 20:20
  • 1
    Pretty well covered by [this post](http://stackoverflow.com/a/8870593/17034). No, Math.Pow() is not faster. Easy to find out for yourself with the Stopwatch class. – Hans Passant Aug 13 '14 at 20:26
  • You should use `Math.Log(x, b)` instead of `Math.Log(x) / Math.Log(b)`, I guess. – Jeppe Stig Nielsen Aug 14 '14 at 10:38

1 Answers1

2

I have built a benchmark as recommended by @Mangist. The code is posted below. I was surprised by the response by @CodesInChaos. I, of course, did some research and realized I could improve a large amount of my code. I will post a link to a interesting StackOverflow article I found in this regard. A number of people had worked out improvements on Math.Pow due to the aforementioned fact.

Thank you again for the suggestions and information.

        int term = 72;
        double contractRate = 2.74 / 1200;
        double balance = 20203.66;
        double pmt = 304.96;
        double logarithm = 0;
        double power = 0;

        DateTime BeginLog = DateTime.UtcNow;
        for (int i = 0; i < 100000000; i++)
        {
            logarithm=(-1*Math.Log(1-(balance*contractRate/pmt))/Math.Log(1+contractRate));
        }
        DateTime EndLog = DateTime.UtcNow;
        Console.WriteLine("Elapsed time= " + (EndLog - BeginLog));
        Console.ReadLine();

        DateTime BeginPow = DateTime.UtcNow;
        for (int i = 0; i < 100000000; i++)
        {
            power = (balance * contractRate * Math.Pow(1 + contractRate, term)) / (Math.Pow(1 
                      +  contractRate, term) - 1);
        }
        DateTime EndPow = DateTime.UtcNow;
        Console.WriteLine("Elapsed time= " + (EndPow - BeginPow));
        Console.ReadLine();

The results of the benchmark were Elapsed time for the logarithm 00:00:04.9274927 Elapsed time for the power 00:00:11.6981697

I also alluded to some additional StackOverflow discussions which shed light on the comment by @CodeInChaos.

How is Math.Pow() implemented in .NET Framework?

Let me add a head to head comparison between a suggestion on the above link and the Math.Pow function. I benchmarked Math.Pow(x,y) against Math.Exp(y*Math.Log(x)) with the following code:

        DateTime PowBeginTime = DateTime.UtcNow;
        for (int i = 0; i < 250000000; i++)
        {
            Math.Pow(1 + contractRate, term);
        }
        DateTime PowEndTime = DateTime.UtcNow;
        Console.WriteLine("Elapsed time= " + (PowEndTime - PowBeginTime));
        Console.ReadLine();

        DateTime HighSchoolBeginTime = DateTime.UtcNow;
        for (int i = 0; i < 250000000; i++)
        {
            Math.Exp(term * Math.Log(1 + contractRate));
        }
        DateTime HighSchoolEndTime = DateTime.UtcNow;
        Console.WriteLine("Elapsed time= " + (HighSchoolEndTime - HighSchoolBeginTime));
        Console.ReadLine();

The results were: Math.Pow(x,y) 00:00:19.9469945 Math.Exp(y*Math.Log(x)) 00:00:18.3478346

Community
  • 1
  • 1
StephenWinburn
  • 107
  • 1
  • 9
  • 1
    In your paragraph "The results of the benchmark were Elapsed time for the logarithm 00:00:04.9274927 Elapsed time for the logarithm 00:00:11.6981697" you indicate twice the result for logarithm but none for power. – vtortola Aug 14 '14 at 13:02
  • Thank you. The latter should have been power. – StephenWinburn Aug 14 '14 at 13:05