Math.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()
结果不是很好(在我的电脑上约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;
    }
}
我检查的第三件事是我是否会通过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
现在我的情况基本上是这样的:不要使用Math for Pow。我唯一的问题就是......我现在真的需要实现自己的数学课吗?对于幂函数来说,实现一个自己的类似乎无效。 (顺便说一句,PowLoop和Pow7在Release版本中的速度甚至更快了~25%,而Math.Pow却没有)。 所以我最后的问题是 a)如果我根本不使用Math.Pow(但对于分数可能),我是错的(这让我感到难过)。 b)如果你有优化的代码,你是否真的直接编写所有这些数学运算? c)可能已经存在用于数学运算的更快(开源^^)库 d)我的问题的根源基本上是:我假设.NET Framework本身已经为这样的基本操作提供了非常优化的代码/编译结果 - 无论是Math-Class还是处理数组,我有点惊讶有多少好处我会通过编写自己的代码来获益。在C#中是否有一些其他的,一般的“字段”或其他内容,我不能直接信任C#。     
已邀请:
要记住两件事: 您可能不需要优化这段代码。你在不到一秒的时间内完成了对该功能的一百万次调用。这真的会导致你的程序出现大问题吗? 无论如何,
Math.Pow
可能是相当优化的。在猜测中,它将调用一个用较低级语言编写的适当的数字库,这意味着你不应该期望数量级增加。 数值编程比你想象的更难。即使您认为自己知道如何计算的算法也不是这样计算的。例如,当您计算平均值时,您不应该只是将数字相加并除以您拥有的数字。 (现代数字库使用两遍例程来纠正浮点错误。) 也就是说,如果您确定您确实需要优化,那么请考虑使用整数而不是浮点值,或将其外包给另一个数字库。     
首先,整数运算比浮点运算快得多。如果不需要浮点值,请不要使用浮点数据类型。这通常适用于任何编程语言。 其次,正如你自己所说,
Math.Pow
可以处理实物。它使用了比简单循环更复杂的算法。难怪它比简单循环慢。如果你摆脱了循环并且只进行了n次乘法,那么你也会减少设置循环的开销 - 从而使它更快。但是如果你不使用循环,你必须知道 预先指数的值 - 它不能在运行时提供。 我不太确定为什么
Math.Exp
Math.Log
更快。但是如果你使用
Math.Log
,就无法找到负值的力量。 基本上
int
更快,避免循环避免额外的开销。但是当你选择这些时,你会获得一些灵活性。但是当你需要的只是整数时,避免实时通常是一个好主意,但是在这种情况下编写一个已经存在的自定义函数似乎有点太多了。 你必须问自己的问题是这是否值得。
Math.Pow
实际上是在减慢你的程序吗?无论如何,已经与你的语言捆绑在一起的
Math.Pow
通常是最快或非常接近的。如果你真的想要制作一个真正通用的替代实现(即不仅限于整数,正值等),你最终可能会使用默认实现中使用的相同算法。     
当你谈论对一行代码进行一百万次迭代时,显然每一个小细节都会有所不同。 Math.Pow()函数调用将比手动4 * 4 ... * 4示例慢得多。 不要编写自己的类,因为它可以编写比标准Math类更优化的东西。     

要回复问题请先登录注册