【问题标题】:Comparing Math.Log and Math.Pow比较 Math.Log 和 Math.Pow
【发布时间】:2014-08-13 19:51:03
【问题描述】:

我正在处理年金,我的代码中有以下方法:

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;
}

我使用前一种方法来确定贷款的支付是否会确保贷款在其剩余期限内还清。我使用后一种方法来确定付款是否针对每月以外的付款期进行报价,如果是,则将其替换为每月付款。经过反思,我可以将后一种方法用于这两项任务。

考虑到这一点,我想知道是否有人知道 Math.Pow 是否比 Math.Log 更快/更有效/相对于 Math.Log?
我认为 Math.Pow 是更好的选择,但希望能提供一些意见。

【问题讨论】:

  • 为什么不使用 100,000 次调用来分析每种方法,然后自己看看哪个更快?
  • 我希望具有固定基数的logpow 快,因为pow 通常是通过在基数上调用log 来实现的,然后是一个固定的基数求幂函数。如果您进行基准测试,请分别针对 x64 和 x86 进行基准测试,因为在这些平台上生成的浮点代码非常不同。
  • 除非这是您的应用程序的瓶颈,否则请使用更易于阅读的版本,而不是更快的版本。
  • 我注意到Term 是一个整数。对于整数幂,通常有比 Math.Pow 更快的方法,例如 mindprod.com/jgloss/power.html。只有当这是性能瓶颈时才走这条路线。
  • this post 很好地覆盖了。不,Math.Pow() 并不快。通过 Stopwatch 课程,您可以轻松找到自己。

标签: c# math benchmarking logarithm pow


【解决方案1】:

我已经按照@Mangist 的建议建立了一个基准。代码贴在下面。我对@CodesInChaos 的回应感到惊讶。当然,我做了一些研究,并意识到我可以改进大量的代码。我将发布一个链接,指向我在这方面找到的一篇有趣的 StackOverflow 文章。由于上述事实,许多人已经对 Math.Pow 进行了改进。

再次感谢您的建议和信息。

        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();

基准测试的结果是 对数的经过时间 00:00:04.9274927 电源经过的时间 00:00:11.6981697

我还提到了一些额外的 StackOverflow 讨论,这些讨论揭示了 @CodeInChaos 的评论。

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

让我在上述链接上的建议与 Math.Pow 函数之间进行头对头比较。我使用以下代码对 Math.Pow(x,y) 和 Math.Exp(y*Math.Log(x)) 进行了基准测试:

        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();

结果是: Math.Pow(x,y) 00:00:19.9469945 Math.Exp(y*Math.Log(x)) 00:00:18.3478346

【讨论】:

  • 在您的段落“基准测试的结果是对数的经过时间 00:00:04.9274927 对数的经过时间 00:00:11.6981697”您表示对数的结果是对数的两倍,但对于功率却没有.
  • 谢谢。后者应该是权力。
猜你喜欢
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
  • 2014-09-17
相关资源
最近更新 更多