【发布时间】:2011-03-04 10:09:22
【问题描述】:
我正在开发一个扩展 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;
}
}
我检查的第三件事是我是否将 Math.Pow(4,7) 直接替换为 4*4*4*4*4*4*4。
结果是(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
现在我现在的情况基本上是这样的:不要用数学来做 Pow。我唯一的问题是……我现在真的必须实现自己的数学课吗?仅仅为 power 函数实现一个自己的类似乎有点无效。 (顺便说一句。PowLoop 和 Pow7 在 Release 版本中甚至快了约 25%,而 Math.Pow 则不然)。
所以我最后的问题是
a) 如果我根本不使用 Math.Pow(但可能是分数)(这让我有点难过),那我错了。
b) 如果你有代码要优化,你真的是直接写所有这些数学运算吗?
c) 可能已经有一个更快的(开源^^)数学运算库
d) 我的问题的来源基本上是:我假设 .NET Framework 本身已经为这些基本操作提供了非常优化的代码/编译结果 - 无论是 Math-Class 还是处理数组,我有点惊讶通过编写自己的代码,我将获得多少好处。在我不能直接信任 C# 的 C# 中是否有一些其他的通用“字段”或其他东西需要注意。
【问题讨论】:
-
我认为 4*4*4*4*4*4*4 将在编译时进行评估,因此它的速度非常快。
-
我认为对于大多数人来说,100 毫秒左右并不是什么大问题。对于大多数人来说,C# 通常不是此类应用程序的首选。
-
你测试过更大的数字吗?我认为 Math.Pow 针对更大的指数进行了优化,并且执行以下操作:x^7 == x^{3+3+1} == {x ^ 3 + x^3 x},这意味着它正在运行顺序大约是 O(log(n) ),而您的解决方案是 O(n),对于大指数来说可能会慢得多。
-
两个最终测试(Pow7 和静态)都是编译器可优化的,因此不像以前那样通用。
-
Math.Pow确实应该有一个重载,它需要一个int指数,因为这是最常见的情况,它会运行得更快。