c# .net performance pow

c# - Math.Pow vs multiplicar operador(rendimiento)



math.pow java (10)

Acabo de probar esto ayer, luego vi tu pregunta ahora.

En mi máquina, un Core 2 Duo que ejecuta 1 hilo de prueba, es más rápido de usar multiplicar hasta un factor de 9. En 10, Math.Pow (b, e) es más rápido.

Sin embargo, incluso en un factor de 2, los resultados a menudo no son idénticos. Hay errores de redondeo.

Algunos algoritmos son muy sensibles a los errores de redondeo. Literalmente tuve que realizar más de un millón de pruebas aleatorias hasta que descubrí esto.

¿Alguien sabe si el operador multiplicar es más rápido que usar el método Math.Pow? Me gusta:

n * n * n

vs

Math.Pow ( n, 3 )


Acabo de reinstalar Windows, así que Visual Studio no está instalado y el código es feo.

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; } }

Los resultados:
csc / o test.cs

test.exe

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

Exponerse a la cuadratura (ver https://.com/questions/101439/the-most-efficient-way-to-implement-an-integer-based-power-function-powint-int ) es mucho más rápido que Math.Pow en mi prueba (mi CPU es un Pentium T3200 a 2 Ghz)

EDITAR: la versión .NET es 3.5 SP1, el sistema operativo es Vista SP1 y el plan de energía es de alto rendimiento.


Algunas reglas básicas de más de 10 años de optimización en procesamiento de imágenes y computación científica:

Las optimizaciones a nivel algorítmico superan cualquier cantidad de optimización a un nivel bajo. A pesar de "Escriba lo obvio, luego optimice" la sabiduría convencional, esto debe hacerse al comienzo. No después de.

Las operaciones matemáticas codificadas a mano (especialmente los tipos SIMD SSE +) generalmente superarán a las comprobadas por error, generalizadas, incorporadas.

Cualquier operación en la que el compilador sepa de antemano lo que debe hacerse es optimizada por el compilador. Estos incluyen: 1. Operaciones de memoria como Array.Copy () 2. Para bucles sobre arreglos donde se proporciona la longitud del arreglo. Como en for ( ..; i<array.Length;.. )

Siempre establece metas poco realistas (si quieres).



Básicamente, debes hacer un benchmark para ver.

Conjeturas educadas (no confiable):

En caso de que no esté optimizado para lo mismo por algún compilador ...

Es muy probable que x * x * x sea ​​más rápido que Math.Pow(x, 3) ya que Math.Pow tiene que lidiar con el problema en su caso general, lidiando con poderes fraccionarios y otros problemas, mientras que x * x * x haría solo toma un par de instrucciones de multiplicación, por lo que es muy probable que sea más rápido.


Esto es tan pequeño que probablemente debería evaluarlo para plataformas específicas, no creo que los resultados para un Pentium Pro sean necesariamente los mismos que para un ARM o Pentium II.

En general, es muy probable que sea totalmente irrelevante.


Lo verifiqué, y Math.Pow() está definido para tomar dos dobles. Esto significa que no puede hacer multiplicaciones repetidas, pero tiene que usar un enfoque más general. Si hubiera un Math.Pow(double, int) , probablemente podría ser más eficiente.

Dicho esto, la diferencia de rendimiento es casi absolutamente absolutamente trivial, por lo que debe usar lo que sea más claro. Las microoptimizaciones de este tipo casi siempre carecen de sentido, se pueden introducir prácticamente en cualquier momento y deben dejarse para el final del proceso de desarrollo. En ese momento, puede verificar si el software es demasiado lento, dónde están los puntos calientes y gastar su esfuerzo de microoptimización donde realmente hará una diferencia.


No estoy de acuerdo con que las funciones construidas a mano sean siempre más rápidas. Las funciones de coseno son mucho más rápidas y más precisas que cualquier otra cosa que pudiera escribir. En cuanto a pow (). Hice una prueba rápida para ver qué tan lento era Math.pow () en javascript, porque Mehrdad advirtió contra las conjeturas.

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

aquí están los resultados:

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

Si no está de acuerdo, pruebe el programa en http://www.m0ose.com/javascripts/speedtests/powSpeedTest.html


Usemos la convención x ^ n. Supongamos que n es siempre un número entero.

Para valores pequeños de n, la multiplicación aburrida será más rápida, porque Math.Pow (probablemente, dependiente de la implementación) utiliza algoritmos sofisticados para permitir que n sea no integral y / o negativo.

Para valores grandes de n, Math.Pow probablemente sea más rápido, pero si su biblioteca no es muy inteligente, usará el mismo algoritmo, lo cual no es ideal si sabe que n es siempre un número entero. Para eso, podrías codificar una implementación de exponenciación por cuadratura o algún otro algoritmo sofisticado.

Por supuesto, las computadoras modernas son muy rápidas y probablemente debería seguir el método más simple, más fácil de leer, con menos probabilidades de tener errores hasta que haga una evaluación comparativa de su programa y esté seguro de que obtendrá un aumento de velocidad significativo utilizando un algoritmo diferente.


Math.Pow(x, y) normalmente se calcula internamente como Math.Exp(Math.Log(x) * y) . La ecuación de potencia de Evey requiere encontrar un registro natural, una multiplicación y elevar e a una potencia.

Como mencioné en mi respuesta anterior, solo a una potencia de 10 Math.Pow() vuelve más rápido, pero la precisión se verá comprometida si se usan una serie de multiplicaciones.