43

任何人都知道乘法运算符是否比使用 Math.Pow 方法更快?像:

n * n * n

对比

Math.Pow ( n, 3 )
4

9 回答 9

46

我刚刚重新安装了 Windows,所以没有安装 Visual Studio,代码很丑

using System;
using System.Diagnostics;

public static class test{

public static void Main(string[] args){
    MyTest();
    PowTest();
}

static void PowTest(){
    var sw = Stopwatch.StartNew();
    double res = 0;
    for (int i = 0; i < 333333333; i++){
        res = Math.Pow(i,30); //pow(i,30)
    }
    Console.WriteLine("Math.Pow: " + sw.ElapsedMilliseconds + " ms:  " + res);
}

static void MyTest(){
    var sw = Stopwatch.StartNew();
    double res = 0;
    for (int i = 0; i < 333333333; i++){
        res = MyPow(i,30);
    }
    Console.WriteLine("MyPow: " + sw.ElapsedMilliseconds + " ms:  " + res);
}



static double MyPow(double num, int exp)
{
    double result = 1.0;
    while (exp > 0)
    {
        if (exp % 2 == 1)
            result *= num;
        exp >>= 1;
        num *= num;
    }

    return result;
}
}

结果:
csc /o test.cs

测试程序

MyPow: 6224 ms:  4.8569351667866E+255  
Math.Pow: 43350 ms:  4.8569351667866E+255 

通过平方求幂(参见https://stackoverflow.com/questions/101439/the-most-efficient-way-to-implement-an-integer-based-power-function-powint-int)比 Math.Pow 快得多在我的测试中(我的 CPU 是 2 Ghz 的 Pentium T3200)

编辑:.NET 版本是 3.5 SP1,操作系统是 Vista SP1,电源计划是高性能的。

于 2009-06-01T21:33:54.510 回答
36

基本上,您应该进行基准测试

受过教育的猜测(不可靠):

如果某些编译器没有针对同一事物进行优化...

这很可能x * x * xMath.Pow(x, 3)Math.Pow一般情况下处理问题、处理分数幂和其他问题要快,而x * x * x只需要几个乘法指令,所以它很可能更快。

于 2009-06-01T20:16:41.623 回答
11

10 多年图像处理和科学计算优化的经验法则:

算法级别的优化胜过任何低级别的优化。尽管“写显而易见,然后优化”的传统智慧,这必须在一开始就完成。不是之后。

手工编码的数学运算(尤其是 SIMD SSE+ 类型)通常会优于完全错误检查的通用内置运算。

编译器预先知道需要做什么的任何操作都由编译器优化。其中包括: 1. 内存操作,例如 Array.Copy() 2. 给定数组长度的数组上的 For 循环。如 ( ..; i<array.Length;..)

总是设定不切实际的目标(如果你愿意的话)。

于 2011-06-08T03:07:08.040 回答
8

我昨天碰巧测试了这个,然后现在看到了你的问题。

在我的机器上,运行 1 个测试线程的 Core 2 Duo,使用乘法到 9 倍会更快。在 10 时,Math.Pow(b, e) 更快。

然而,即使是 2 倍,结果也常常不相同。存在舍入误差。

一些算法对舍入误差高度敏感。在我发现这一点之前,我不得不进行超过一百万次随机测试。

于 2012-05-20T12:10:47.950 回答
5

这太微不足道了,您可能应该针对特定平台对其进行基准测试,我认为 Pentium Pro 的结果不一定与 ARM 或 Pentium II 的结果相同。

总而言之,它很可能完全无关紧要。

于 2009-06-01T20:22:29.943 回答
4

我检查了,并被Math.Pow()定义为采取两个双打。这意味着它不能进行重复乘法,而是必须使用更通用的方法。如果有Math.Pow(double, int),它可能会更有效。

话虽如此,性能差异几乎可以肯定是微不足道的,因此您应该使用更清晰的那个。像这样的微优化几乎总是毫无意义的,几乎可以在任何时候引入,并且应该留到开发过程的最后。那时,您可以检查软件是否太慢,热点在哪里,然后将您的微优化工作花在真正会产生影响的地方。

于 2009-06-01T20:29:30.617 回答
2

让我们使用约定 x^n。假设 n 始终是一个整数。

对于较小的 n 值,无​​聊的乘法会更快,因为 Math.Pow(可能取决于实现)使用花哨的算法来允许 n 为非整数和/或负数。

对于较大的 n 值,Math.Pow 可能会更快,但如果您的库不是很聪明,它将使用相同的算法,如果您知道 n 始终是整数,这并不理想。为此,您可以通过平方或其他一些花哨的算法来编写求幂的实现。

当然,现代计算机速度非常快,您可能应该坚持使用最简单、最容易阅读、最不可能出错的方法,直到您对程序进行基准测试并确定使用不同的算法会获得显着的加速。

于 2009-06-01T20:39:22.797 回答
2

Math.Pow(x, y)通常在内部计算为Math.Exp(Math.Log(x) * y)。每个幂方程都需要找到自然对数、乘法并e求幂。

正如我在之前的回答中提到的,只有 10 的幂会Math.Pow()变得更快,但是如果使用一系列乘法,准确性会受到影响。

于 2017-07-22T09:02:20.413 回答
0

我不同意手工构建的功能总是更快。余弦函数比我能写的任何东西都更快、更准确。至于 pow()。我做了一个快速测试,看看 Math.pow() 在 javascript 中有多慢,因为 Mehrdad 告诫不要猜测

    for (i3 = 0; i3 < 50000; ++i3) { 
      for(n=0; n < 9000;n++){ 
        x=x*Math.cos(i3);
      }
    }

结果如下:

Each function run 50000 times 

time for 50000 Math.cos(i) calls = 8 ms 
time for 50000 Math.pow(Math.cos(i),9000) calls = 21 ms 
time for 50000 Math.pow(Math.cos(i),9000000) calls = 16 ms 
time for 50000 homemade for loop calls 1065 ms

如果您不同意,请尝试http://www.m0ose.com/javascripts/speedtests/powSpeedTest.html上的程序

于 2011-11-20T18:31:37.077 回答