Математика.Pow против оператора умножения (производительность)
-
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()
становится быстрее, но точность будет снижена при использовании серии умножений.