Math.Pow против оператора умножения (производительность) - PullRequest
29 голосов
/ 02 июня 2009

Кто-нибудь знает, работает ли оператор умножения быстрее, чем метод Math.Pow? Как:

n * n * n

против

Math.Pow ( n, 3 )

Ответы [ 10 ]

40 голосов
/ 02 июня 2009

Я просто переустановил 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

test.exe

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

Вычисление по квадрату (см. /80558/naibolee-effektivnyi-sposob-realizatsii-tselochislennoi-stepennoi-funktsii-pow-int-int) намного быстрее, чем Math.Pow в моем тесте (мой процессор - Pentium T3200 с частотой 2 ГГц)

РЕДАКТИРОВАТЬ: .NET версия 3.5 SP1, ОС Vista Vista SP1 и план питания с высокой производительностью.

29 голосов
/ 02 июня 2009

По сути, вы должны тест , чтобы увидеть.

Обученная догадка (ненадежная):

На случай, если какой-то компилятор не оптимизирует его до того же самого ...

Весьма вероятно, что x * x * x быстрее, чем Math.Pow(x, 3), поскольку Math.Pow должен решать проблему в общем случае, касающуюся дробных степеней и других вопросов, тогда как x * x * x просто потребует пару инструкций умножения так что, скорее всего, будет быстрее.

7 голосов
/ 08 июня 2011

Несколько правил из 10+ лет оптимизации обработки изображений и научных вычислений:

Оптимизация на алгоритмическом уровне побеждает любую оптимизацию на низком уровне. Несмотря на общепринятое мнение «напиши очевидное, а затем оптимизируй», это необходимо сделать с самого начала. Не после.

Математические операции с ручным кодированием (особенно SIMD SSE +) обычно превосходят полностью проверенные встроенные встроенные ошибки.

Любая операция, в которой компилятор заранее знает, что нужно сделать, оптимизируется компилятором. Они включают: 1. Операции с памятью, такие как Array.Copy () 2. Для циклов над массивами, где указана длина массива. Как в (..; i<array.Length;..)

Всегда ставьте нереальные цели (если хотите).

6 голосов
/ 20 мая 2012

Я только что проверил это вчера, а потом увидел ваш вопрос.

На моей машине, Core 2 Duo, в которой запущен 1 тестовый поток, умножение выполняется быстрее с коэффициентом 9. В 10 Math.Pow (b, e) быстрее.

Однако даже при коэффициенте 2 результаты часто не идентичны. Есть ошибки округления.

Некоторые алгоритмы очень чувствительны к ошибкам округления. Мне пришлось буквально выполнить миллион случайных тестов, пока я не обнаружил это.

4 голосов
/ 02 июня 2009

Я проверил, и Math.Pow() определено, чтобы взять две пары. Это означает, что он не может делать повторные умножения, но должен использовать более общий подход. Если бы был Math.Pow(double, int), он мог бы быть более эффективным.

При этом разница в производительности почти наверняка абсолютно тривиальна, и поэтому вы должны использовать то, что яснее. Подобные микрооптимизации почти всегда бессмысленны, их можно вводить практически в любое время, и их следует оставить для завершения процесса разработки. В этот момент вы можете проверить, не слишком ли медленно работает программное обеспечение, где находятся «горячие точки», и провести свои усилия по микрооптимизации там, где это действительно будет иметь значение.

4 голосов
/ 02 июня 2009

Это настолько микро, что вам, вероятно, стоит сравнить его с конкретными платформами, я не думаю, что результаты для Pentium Pro будут обязательно такими же, как для ARM или Pentium II.

В целом, это, скорее всего, совершенно не имеет значения.

2 голосов
/ 02 июня 2009

Давайте использовать соглашение x ^ n. Давайте предположим, что n всегда является целым числом.

Для малых значений n скучное умножение будет быстрее, потому что Math.Pow (вероятно, зависит от реализации) использует причудливые алгоритмы, чтобы n было нецелым и / или отрицательным.

При больших значениях n Math.Pow, скорее всего, будет быстрее, но если ваша библиотека не очень умная, она будет использовать тот же алгоритм, который не идеален, если вы знаете, что n всегда является целым числом. Для этого вы можете кодировать реализацию возведения в степень, возводя в квадрат или какой-то другой причудливый алгоритм.

Конечно, современные компьютеры работают очень быстро, и вам, вероятно, следует придерживаться самого простого, легкочитаемого, наименее вероятного метода с ошибками, пока вы не сравните тест программы и не будете уверены, что вы получите значительное ускорение при использовании другого алгоритма.

1 голос
/ 20 ноября 2011

Я не согласен с тем, что встроенные функции всегда быстрее. Функции косинуса намного быстрее и точнее, чем все, что я мог написать. Что касается Pow (). Я быстро проверил, насколько медленным был Math.pow () в javascript, потому что Мехрдад предостерегал от догадок

    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

1 голос
/ 02 июня 2009

Здесь обсуждается тема встроенного умножения против Math.pow

Очевидно Math.pow медленнее, но не намного ...

0 голосов
/ 22 июля 2017

Math.Pow(x, y) обычно рассчитывается как Math.Exp(Math.Log(x) * y). Каждое уравнение мощности требует нахождения натурального логарифма, умножения и возведения e в степень.

Как я уже упоминал в моем предыдущем ответе, только при степени 10 Math.Pow() становится быстрее, но точность будет снижена при использовании серии умножений.

...