Математика.Pow против оператора умножения (производительность)

StackOverflow https://stackoverflow.com/questions/936541

  •  06-09-2019
  •  | 
  •  

Вопрос

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

n * n * n

против

Math.Pow ( n, 3 )
Это было полезно?

Решение

В принципе, вам следует эталонный показатель чтобы увидеть.

Обоснованные догадки (ненадежны):

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

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

Другие советы

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

test.exe

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) намного быстрее, чем математика.Pow в моем тесте (мой процессор Pentium T3200 с частотой 2 ГГц)

Редактировать:Версия .NET - 3.5 SP1, ОПЕРАЦИОННАЯ система - Vista SP1, а план питания - high performance.

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

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

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

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

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

Я просто случайно протестировал это вчера, а затем увидел ваш вопрос сейчас.

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

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

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

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

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

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

В общем, скорее всего, это будет совершенно неуместно.

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

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

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

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

Я не согласен с тем, что функции, созданные вручную, всегда работают быстрее.Функции косинуса намного быстрее и точнее, чем все, что я мог бы написать.Что касается 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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top