Кто-нибудь знает, работает ли оператор умножения быстрее, чем с помощью метода Math.Pow? Как:
n * n * n
против
Math.Pow ( n, 3 )
Кто-нибудь знает, работает ли оператор умножения быстрее, чем с помощью метода Math.Pow? Как:
n * n * n
против
Math.Pow ( n, 3 )
В принципе, вы должны проверить.
В случае, если какой-либо компилятор не оптимизирован к одному и тому же...
Очень вероятно, что x * x * x
быстрее, чем Math.Pow(x, 3)
, поскольку Math.Pow
должен иметь дело с проблемой в общем случае, имея дело с дробными полномочиями и другими проблемами, тогда как x * x * x
просто возьмет пару инструкций умножения, поэтому он, скорее всего, будет быстрее.
Я просто переустановил окна, поэтому визуальная студия не установлена и код уродливый
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
Экспоненциация по квадрату (см. fooobar.com/questions/32345/...) намного быстрее, чем Math.Pow в моем тесте (мой процессор - Pentium T3200 при 2 ГГц)
EDIT: версия .NET - 3.5 SP1, ОС - Vista SP1, а план мощности - высокая.
Я только что проверил это вчера, а затем увидел ваш вопрос.
На моей машине Core 2 Duo работает 1 тестовый поток, быстрее использовать умножить до 9 раз. В 10, Math.Pow(b, e) выполняется быстрее.
Однако даже в 2 раза результаты часто не идентичны. Имеются ошибки округления.
Некоторые алгоритмы очень чувствительны к ошибкам округления. Мне пришлось буквально пробежать миллион случайных тестов, пока я не обнаружил это.
Это так микро, что вы, вероятно, должны сравнивать его для определенных платформ, я не думаю, что результаты для Pentium Pro будут обязательно такими же, как для ARM или Pentium II.
В целом, это, скорее всего, совершенно не имеет значения.
Я проверил, и Math.Pow()
определено, чтобы взять два удвоения. Это означает, что он не может выполнять повторные умножения, но должен использовать более общий подход. Если бы был Math.Pow(double, int)
, он мог бы быть более эффективным.
Говоря это, разница в производительности почти наверняка абсолютно тривиальна, и поэтому вы должны использовать то, что лучше. Микрооптимизации, подобные этому, почти всегда бессмысленны, могут быть введены практически в любое время и должны быть оставлены для завершения процесса разработки. В этот момент вы можете проверить, слишком ли медленное программное обеспечение, где находятся "горячие точки", и потратить свое усилие на микро-оптимизацию, где это действительно будет иметь значение.
Несколько эмпирических указаний от 10 лет оптимизации в обработке изображений и научных вычислениях:
Оптимизации на уровне алгоритма избивают любое количество оптимизации на низком уровне. Несмотря на то, что "Напиши очевидное, а затем оптимизируйте" общепринятую мудрость, это нужно сделать с самого начала. Не после.
Обработанные вручную математические операции (особенно типы SIMD SSE +), как правило, превосходят полностью проверенные ошибки, обобщенные встроенные.
Любая операция, когда компилятор заранее знает, что нужно сделать, оптимизируется компилятором. К ним относятся:
1. Операции памяти, такие как Array.Copy()
2. Для циклов над массивами, где задана длина массива. Как и для (..; i<array.Length;..
)
Всегда задавайте нереалистичные цели (если хотите).
Ниже приведено обсуждение темы вложенное умножение против Math.pow
По-видимому, Math.pow медленнее, но не намного...
Пусть используется соглашение 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)
. Evey уравнение требует поиска естественного логарифма, умножения и повышения e
до степени.
Как я уже упоминал в своем предыдущем ответе, только при мощности 10 Math.Pow()
становится быстрее, но точность будет скомпрометирована при использовании серии умножений.