Me sorprendió la diferencia de tiempo que Daniel Lichtblau pointed out de dos maneras de llegar a las diferencias entre el número de factores primos (PrimeOmega
) y el número de distintos factores primos (PrimeNu
) de un entero, n. Así que decidí analizarlo un poco más.¿Por qué la eficiencia relativa de estas rutinas en Mathematica?
Las funciones g1
y g2
a continuación son pequeñas variaciones del ones Daniel utilizado, así como de otros tres. Todos devuelven la cantidad de enteros sin cuadrados desde 1 hasta n. Pero las diferencias son bastante dramáticas. ¿Alguien puede explicar las razones detrás de las diferencias? En particular, ¿por qué el Sum
en g5
proporciona tal ventaja de velocidad?
g1[n_] := Count[PrimeOmega[Range[n]] - PrimeNu[Range[n]], 0]
g2[n_] := Count[With[{fax = FactorInteger[#]},
Total[fax[[All, 2]]] - Length[fax]] & /@ Range[n], 0]
g3[n_] := Count[SquareFreeQ/@ Range[n], True]
(* g3[n_] := Count[SquareFreeQ[#] & /@ Range[n], True] Mr.Wizard's suggestion
incorporated above. Better written but no significant increase in speed. *)
g4[n_] := n - Count[MoebiusMu[Range[n]], 0]
g5[n_] := Sum[MoebiusMu[d]*Floor[(n - 1)/d^2], {d, 1, Sqrt[n - 1]}]
La comparación:
n = 2^20;
Timing[g1[n]]
Timing[g2[n]]
Timing[g3[n]]
Timing[g4[n]]
Timing[g5[n]]
Los resultados:
{44.5867, 637461}
{11.4228, 637461}
{4.43416, 637461}
{1.00392, 637461}
{0.004478, 637461}
Editar:
Mysticial planteó la posibilidad de que este último ro utines estaban cosechando los beneficios de su orden, que algo de almacenamiento en caché puede haber estado sucediendo.
Así que vamos a ejecutar la comparación en el orden inverso:
n = 2^20;
Timing[g5[n]]
Timing[g4[n]]
Timing[g3[n]]
Timing[g2[n]]
Timing[g1[n]]
resultados de las comparaciones Invertida:
{0.003755, 637461}
{0.978053, 637461}
{4.59551, 637461}
{11.2047, 637461}
{44.5979, 637461}
veredicto: Una suposición razonable, pero no respaldadas por los datos.
¿Quién o qué es RedNine? –
btw, 'SquareFreeQ [#] &/@ Range [n]' es detallado; 'SquareFreeQ/@ Range [n]' debería ser suficiente. –
Elaboración del comentario anterior: normalmente solo debería ver una función pura de la forma 'función [#] &' si necesita extraer el primer elemento de una expresión. Por ejemplo, en lugar de 'Sqrt [First [#]] &/@ {{2, 4, 6}, {8, 10, 12}}' puede escribir 'Sqrt [#] & @@@ {{2, 4, 6}, {8, 10, 12}} ' –