Math.Pow的最佳实践

S. *_*ter 7 .net c# pow

我正在开发一个扩展OpenCV,HALCON,...的图像处理库.该库必须与.NET Framework 3.5一起使用,并且由于我对.NET的经验有限,我想问一些有关性能的问题.

我遇到了一些我无法正确解释的具体事情,并希望你问a)为什么和b)处理案件的最佳做法是什么.

我的第一个问题是关于Math.pow.我已经在StackOverflow上找到了一些答案,这很好地解释了它(a)但不知道如何处理(b).我的基准程序看起来像这样

Stopwatch watch = new Stopwatch();  // from the Diagnostics class
watch.Start();
for (int i = 0; i < 1000000; i++)
    double result = Math.Pow(4,7)   // the function call
watch.Stop()
Run Code Online (Sandbox Code Playgroud)

结果不是很好(在我的电脑上约300毫秒)(我已经运行了10次测试并计算了平均值).

我的第一个想法是检查这是因为它是一个静态功能.所以我实现了自己的课程

class MyMath
{
    public static double Pow (double x, double y)   //Using some expensive functions to calculate the power
    {
        return Math.Exp(Math.Log(x) * y);
    }

    public static double PowLoop (double x, int y)  // Using Loop
    {
        double res = x;
        for(int i = 1; i < y; i++)
            res *= x;
        return res;
    }

    public static double Pow7 (double x)            // Using inline calls
    {
        return x * x * x * x * x * x * x;
    }
}
Run Code Online (Sandbox Code Playgroud)

我检查的第三件事是我是否会通过4*4*4*4*4*4*4直接替换Math.Pow(4,7).

结果是(10次试运行中的平均值)

300 ms   Math.Pow(4,7)
356 ms   MyMath.Pow(4,7)    //gives wrong rounded results
264 ms   MyMath.PowLoop(4,7)
 92 ms   MyMath.Pow7(4)
 16 ms   4*4*4*4*4*4*4
Run Code Online (Sandbox Code Playgroud)

现在我的情况基本上是这样的:不要使用Math for Pow.我唯一的问题就是......我现在真的需要实现自己的数学课吗?对于幂函数来说,实现一个自己的类似乎无效.(顺便说一句,PowLoop和Pow7在Release版本中的速度甚至更快了~25%,而Math.Pow却没有).

所以我最后的问题是

a)如果我根本不使用Math.Pow(但对于分数可能),我是错的(这让我感到难过).

b)如果你有优化的代码,你是否真的直接编写所有这些数学运算?

c)可能已经存在用于数学运算的更快(开源^^)库

d)我的问题的根源基本上是:我假设.NET Framework本身已经为这样的基本操作提供了非常优化的代码/编译结果 - 无论是Math-Class还是处理数组,我有点惊讶有多少好处我会通过编写自己的代码来获益.在C#中是否还有一些其他的,一般的"字段"或其他内容,我不能直接信任C#.

Ric*_*ton 5

要记住两件事:

  1. 您可能不需要优化这段代码。您刚刚在不到一秒钟的时间内完成了对函数的一百万次调用。这真的会在你的程序中引起大问题吗?

  2. Math.Pow无论如何可能是相当理想的。猜测它会调用一个用低级语言编写的适当的数字库,这意味着您不应该期望数量级增加。

  3. 数值编程比你想象的要难。即使你认为你知道如何计算的算法,也不是那样计算的。例如,当您计算平均值时,您不应该只是将数字相加并除以您拥有的数字数量。(现代数字库使用两遍例程来纠正浮点错误。)

也就是说,如果您决定确实需要优化,那么请考虑使用整数而不是浮点值,或者将其外包给另一个数字库。


cus*_*ar9 0

当您谈论对一行代码进行一百万次迭代时,显然每个小细节都会产生影响。

Math.Pow() 是一个函数调用,它比您的手动 4*4...*4 示例慢得多。

不要编写自己的类,因为您是否能够编写比标准 Math 类更优化的内容值得怀疑。