¿Cuál sería el algoritmo más óptimo (en cuanto al rendimiento) para calcular el número de divisores de un número dado?
Sería genial si pudieras proporcionar un pseudocódigo o un enlace a algún ejemplo.
EDITAR: Todas las respuestas han sido muy útiles, gracias. Estoy implementando el Tamiz de Atkin y luego usaré algo similar a lo que Jonathan Leffler indicó. El enlace publicado por Justin Bozonier tiene más información sobre lo que quería.
performance
algorithm
pseudocode
esquiador
fuente
fuente
Respuestas:
Dmitriy tiene razón en que querrás que el Tamiz de Atkin genere la lista principal, pero no creo que eso se ocupe de todo. Ahora que tiene una lista de números primos, deberá ver cuántos de esos números primos actúan como divisores (y con qué frecuencia).
Aquí hay algo de Python para el algo.Mira aquí y busca "Asunto: matemático - necesita algoritmo de divisores". Sin embargo, solo cuente la cantidad de elementos en la lista en lugar de devolverlos.Aquí hay un Dr. Math que explica qué es exactamente lo que necesita hacer matemáticamente.
Esencialmente, se reduce a si su número
n
es:n = a^x * b^y * c^z
(donde a, byc son los divisores primos de n y x, y, y z son la cantidad de veces que se repite ese divisor), entonces el recuento total de todos los divisores es:
(x + 1) * (y + 1) * (z + 1)
.Editar: Por cierto, para encontrar a, b, c, etc., querrás hacer lo que equivale a algo codicioso si lo entiendo correctamente. Comience con su divisor primo más grande y multiplíquelo por sí mismo hasta que una multiplicación adicional exceda el número n. Luego pase al siguiente factor más bajo y multiplicado por el primo anterior ^ número de veces que se multiplicó por el primo actual y siga multiplicándolo por el primo hasta que el próximo exceda n ... etc. Mantenga un registro de la cantidad de veces que multiplica divisores juntos y aplicar esos números en la fórmula anterior.
No estoy 100% seguro acerca de mi descripción de algo, pero si no es así, es algo similar.
fuente
n = (a^x * b^y * c^z)-(x + 1) * (y + 1) * (z + 1)
es la reglaHay muchas más técnicas para factorizar que el tamiz de Atkin. Por ejemplo, supongamos que queremos factorizar 5893. Bueno, su sqrt es 76.76 ... Ahora intentaremos escribir 5893 como un producto de cuadrados. Bueno (77 * 77 - 5893) = 36, que es 6 al cuadrado, por lo que 5893 = 77 * 77 - 6 * 6 = (77 + 6) (77-6) = 83 * 71. Si eso no hubiera funcionado, habríamos analizado si 78 * 78 - 5893 era un cuadrado perfecto. Y así. Con esta técnica, puede probar rápidamente los factores cercanos a la raíz cuadrada de n mucho más rápido que probando primos individuales. Si combina esta técnica para descartar imprimaciones grandes con un tamiz, tendrá un método de factorización mucho mejor que con el tamiz solo.
Y esta es solo una de las muchas técnicas que se han desarrollado. Este es bastante simple. Le tomaría mucho tiempo aprender, digamos, suficiente teoría de números para comprender las técnicas de factorización basadas en curvas elípticas. (Sé que existen. No los entiendo).
Por lo tanto, a menos que esté tratando con enteros pequeños, no trataría de resolver ese problema yo mismo. En cambio, trataría de encontrar una manera de usar algo como la biblioteca PARI que ya tiene implementada una solución altamente eficiente. Con eso puedo factorizar un número aleatorio de 40 dígitos como 124321342332143213122323434312213424231341 en aproximadamente 0.05 segundos. (Su factorización, en caso de que se lo haya preguntado, es 29 * 439 * 1321 * 157907 * 284749 * 33843676813 * 4857795469949. Estoy bastante seguro de que no resolvió esto usando el tamiz de Atkin ...)
fuente
@Yasky
La función de tus divisores tiene un error porque no funciona correctamente para cuadrados perfectos.
Tratar:
fuente
No estoy de acuerdo con que el tamiz de Atkin sea el camino a seguir, porque podría tomar más tiempo verificar la primalidad de cada número en [1, n] que reducir el número por divisiones.
Aquí hay un código que, aunque ligeramente más pirateado, generalmente es mucho más rápido:
ps Eso está funcionando código python para resolver este problema.
fuente
Aquí hay un algoritmo directo de O (sqrt (n)). Usé esto para resolver el proyecto euler
fuente
Esta interesante pregunta es mucho más difícil de lo que parece, y no ha sido respondida. La pregunta se puede factorizar en 2 preguntas muy diferentes.
1 dado N, encuentre la lista L de factores primos de N
2 dado L, calcular el número de combinaciones únicas
Todas las respuestas que veo hasta ahora se refieren al número 1 y no mencionan que no es manejable para números enormes. Para N de tamaño moderado, incluso números de 64 bits, es fácil; para N enorme, el problema de factorización puede tomar "para siempre". El cifrado de clave pública depende de esto.
La pregunta # 2 necesita más discusión. Si L contiene solo números únicos, es un cálculo simple que usa la fórmula de combinación para elegir k objetos de n elementos. En realidad, debe sumar los resultados de la aplicación de la fórmula mientras varía k de 1 a sizeof (L). Sin embargo, L generalmente contendrá múltiples ocurrencias de múltiples primos. Por ejemplo, L = {2,2,2,3,3,5} es la factorización de N = 360. ¡Ahora este problema es bastante difícil!
Restableciendo el # 2, dada la colección C que contiene k elementos, de modo que el elemento a tiene 'duplicados, y el elemento b tiene b' duplicados, etc. ¿cuántas combinaciones únicas de 1 a k-1 elementos hay? Por ejemplo, {2}, {2,2}, {2,2,2}, {2,3}, {2,2,3,3} deben aparecer una vez y solo una vez si L = {2,2 , 2,3,3,5}. Cada una de estas subcolecciones únicas es un divisor único de N al multiplicar los elementos de la subcolección.
fuente
p_i
es un factor primo de un número conk_i
multiplicidad, el número total de divisores de ese número es(k_1+1)*(k_2+1)*...*(k_n+1)
. Supongo que ya lo sabes, pero lo escribo para el beneficio de un lector aleatorio aquí.Una respuesta a su pregunta depende en gran medida del tamaño del número entero. Los métodos para números pequeños, por ejemplo, menos de 100 bits, y para números ~ 1000 bits (como los utilizados en criptografía) son completamente diferentes.
descripción general: http://en.wikipedia.org/wiki/Divisor_function
valores para
n
referencias pequeñas y algunas útiles: A000005: d (n) (también llamado tau (n) o sigma_0 (n)), el número de divisores de n.ejemplo del mundo real: factorización de enteros
fuente
SOLO una línea.
He pensado con mucho cuidado acerca de su pregunta y he tratado de escribir un código altamente eficiente y eficaz. Para imprimir todos los divisores de un número dado en la pantalla, ¡solo necesitamos una línea de código! (use la opción -std = c99 mientras compila a través de gcc)
para encontrar números de divisores puede usar la siguiente función muy rápida (funciona correctamente para todos los números enteros excepto 1 y 2)
o si trata el número dado como un divisor (funciona correctamente para todos los números enteros excepto 1 y 2)
NOTA: dos funciones anteriores funcionan correctamente para todos los números enteros positivos, excepto los números 1 y 2, por lo que es funcional para todos los números que son mayores que 2, pero si necesita cubrir 1 y 2, puede usar una de las siguientes funciones (un poco más lento)
O
lo pequeño es hermoso :)
fuente
El tamiz de Atkin es una versión optimizada del tamiz de Eratóstenes que da todos los números primos hasta un número entero dado. Debería poder googlear esto para obtener más detalles.
Una vez que tenga esa lista, es simple dividir su número por cada primo para ver si es un divisor exacto (es decir, el resto es cero).
Los pasos básicos para calcular los divisores de un número (n) son [este es un seudocódigo convertido de código real, así que espero no haber introducido errores]:
fuente
Puedes probar este. Es un poco duro, pero es razonablemente rápido.
fuente
Una vez que tenga la factorización prima, hay una manera de encontrar el número de divisores. Agregue uno a cada uno de los exponentes en cada factor individual y luego multiplique los exponentes juntos.
Por ejemplo: 36 Factorización prima: 2 ^ 2 * 3 ^ 2 Divisores: 1, 2, 3, 4, 6, 9, 12, 18, 36 Número de divisores: 9
Suma uno a cada exponente 2 ^ 3 * 3 ^ 3 Multiplica exponentes: 3 * 3 = 9
fuente
Antes de comprometerse con una solución, considere que el enfoque Sieve podría no ser una buena respuesta en el caso típico.
Hace un tiempo hubo una pregunta principal e hice una prueba de tiempo: para enteros de 32 bits, al menos determinar si era primo era más lento que la fuerza bruta. Hay dos factores que suceden:
1) Si bien un humano tarda un tiempo en hacer una división, es muy rápido en la computadora, similar al costo de buscar la respuesta.
2) Si no tiene una tabla principal, puede hacer un bucle que se ejecute completamente en el caché L1. Esto lo hace más rápido.
fuente
Esta es una solución eficiente:
fuente
Los divisores hacen algo espectacular: se dividen por completo. Si desea comprobar el número de divisores de un número,
n
, está claro que es redundante para abarcar todo el espectro,1...n
. No he hecho ninguna investigación en profundidad para esto, pero resolví el problema 12 del Proyecto Euler sobre números triangulares . Mi solución para la prueba de más de 500 divisores funcionó durante 309504 microsegundos (~ 0.3s). Escribí esta función divisor para la solución.Para cada algoritmo, hay un punto débil. Pensé que esto era débil contra los números primos. Pero como los números triangulares no se imprimen, cumplió su propósito sin problemas. Desde mi perfil, creo que lo hizo bastante bien.
Felices vacaciones.
fuente
numberOfDivisors
y el iterador en 1; esto debería deshacerse de la división por cero errorDesea el Tamiz de Atkin, descrito aquí: http://en.wikipedia.org/wiki/Sieve_of_Atkin
fuente
El método del número primo es muy claro aquí. P [] es una lista de números primos menor o igual que sq = sqrt (n);
fuente
Los libros de texto de teoría de números llaman tau a la función de conteo de divisores. El primer hecho interesante es que es multiplicativo, es decir. τ (ab) = τ (a) τ (b), cuando a y b no tienen un factor común. (Prueba: cada par de divisores de a y b da un divisor distinto de ab).
Ahora tenga en cuenta que para pa prime, τ (p ** k) = k + 1 (las potencias de p). Por lo tanto, puede calcular fácilmente τ (n) a partir de su factorización.
Sin embargo, la factorización de grandes números puede ser lenta (la seguridad de la criptografía RSA depende de que el producto de dos números primos grandes sea difícil de factorizar). Eso sugiere este algoritmo optimizado
fuente
El siguiente es un programa en C para encontrar el número de divisores de un número dado.
La complejidad del algoritmo anterior es O (sqrt (n)).
Este algoritmo funcionará correctamente para los números que son cuadrados perfectos, así como los números que no son cuadrados perfectos.
Tenga en cuenta que el límite superior del bucle se establece en la raíz cuadrada del número para tener el algoritmo más eficiente.
Tenga en cuenta que almacenar el límite superior en una variable separada también ahorra tiempo, no debe llamar a la función sqrt en la sección de condición del bucle for, esto también ahorra su tiempo computacional.
En lugar del bucle anterior anterior, también puede usar el siguiente bucle, que es aún más eficiente, ya que elimina la necesidad de encontrar la raíz cuadrada del número.
fuente
Aquí hay una función que escribí. su peor complejidad es O (sqrt (n)), el mejor momento es O (log (n)). Te da todos los divisores primos junto con el número de su ocurrencia.
fuente
Esta es la forma más básica de calcular los divisores de números:
fuente
@Kendall
Probé su código e hice algunas mejoras, ahora es aún más rápido. También probé con el código @ هومن جاویدپور, esto también es más rápido que su código.
fuente
¿No es solo una cuestión de factorizar el número, determinar todos los factores del número? Luego puede decidir si necesita todas las combinaciones de uno o más factores.
Entonces, un posible algoritmo sería:
Depende de usted combinar los factores para determinar el resto de la respuesta.
fuente
Esto es algo que se me ocurrió basado en la respuesta de Justin. Puede requerir alguna optimización.
fuente
Creo que esto es lo que estás buscando. Hago exactamente lo que pediste. Cópielo y péguelo en el Bloc de notas. Guárdelo como * .bat. Ejecute. Ingrese el número. Multiplique el proceso por 2 y ese es el número de divisores. Lo hice a propósito para que determine los divisores más rápido:
Tenga en cuenta que una variable CMD no puede admitir valores superiores a 999999999
fuente
supongo que este será práctico y preciso
script.pyton
>>>factors=[ x for x in range (1,n+1) if n%x==0] print len(factors)
fuente
Pruebe algo en este sentido:
fuente
No conozco el método MÁS eficiente, pero haría lo siguiente:
Debería funcionar \ o /
Si lo necesita, puedo codificar algo mañana en C para demostrarlo.
fuente