¿Cuál es la forma más eficiente de encontrar todos los factores de un número en Python?

142

¿Alguien puede explicarme una forma eficiente de encontrar todos los factores de un número en Python (2.7)?

Puedo crear un algoritmo para hacer esto, pero creo que está mal codificado y lleva demasiado tiempo producir un resultado para un gran número.

Adnan
fuente
3
No se python. Pero esta página puede ser útil para usted es.wikipedia.org/wiki/Integer_factorization
Stan
3
¿Qué tal el uso primefac? pypi.python.org/pypi/primefac
Zubo

Respuestas:

265
from functools import reduce

def factors(n):    
    return set(reduce(list.__add__, 
                ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))

Esto devolverá todos los factores, muy rápidamente, de un número n.

¿Por qué raíz cuadrada como límite superior?

sqrt(x) * sqrt(x) = x. Entonces, si los dos factores son iguales, ambos son la raíz cuadrada. Si aumenta un factor, debe reducir el otro factor. Esto significa que uno de los dos siempre será menor o igual que sqrt(x), por lo que solo tiene que buscar hasta ese punto para encontrar uno de los dos factores coincidentes. Luego puede usar x / fac1para obtener fac2.

El reduce(list.__add__, ...)está tomando las pequeñas listas [fac1, fac2]y uniéndolas en una larga lista.

Las [i, n/i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0declaraciones de un par de factores si el resto cuando se divide npor el más pequeño es cero (no es necesario para comprobar la más grande también, que sólo se pone que al dividir npor la más pequeña.)

En set(...)el exterior, se eliminan los duplicados, lo que solo ocurre con los cuadrados perfectos. Para n = 4, esto volverá 2dos veces, así que setdeshazte de uno de ellos.

agf
fuente
1
Copié y pegué esto de una lista de algoritmos en mi computadora, todo lo que hice fue encapsular el sqrt- probablemente fue antes de que la gente realmente pensara en admitir Python 3. Creo que el sitio donde lo obtuve lo probé __iadd__y fue más rápido . Sin embargo, parece recordar algo sobre x**0.5ser más rápido que sqrt(x)en algún momento, y es más infalible de esa manera.
agf
77
Parece realizar un 15% más rápido si lo uso en if not n % ilugar deif n % i == 0
dansalmo
3
@sthzg Queremos que devuelva un entero, no un flotante, y en Python 3 /devolverá un flotante incluso si ambos argumentos son enteros y son exactamente divisibles, es decir, 4 / 2 == 2.0no 2.
agf
77
Sé que esta es una vieja pregunta, pero en Python 3.x necesita agregar from functools import reducepara que esto funcione.
anonymoose
55
@unseen_rider: Eso no suena bien. ¿Puedes proporcionar algo para respaldarlo?
Ry-
55

La solución presentada por @agf es excelente, pero se puede lograr un tiempo de ejecución ~ 50% más rápido para un número impar arbitrario al verificar la paridad. Como los factores de un número impar siempre son impares, no es necesario verificarlos cuando se trata de números impares.

Acabo de empezar a resolver los acertijos del Proyecto Euler . En algunos problemas, se llama una comprobación de divisor dentro de dos forbucles anidados , y el rendimiento de esta función es, por lo tanto, esencial.

Combinando este hecho con la excelente solución de agf, terminé con esta función:

from math import sqrt
def factors(n):
        step = 2 if n%2 else 1
        return set(reduce(list.__add__,
                    ([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))

Sin embargo, en números pequeños (~ <100), la sobrecarga adicional de esta alteración puede hacer que la función tarde más.

Realicé algunas pruebas para verificar la velocidad. A continuación se muestra el código utilizado. Para producir las diferentes parcelas, alteré el X = range(1,100,1)correspondiente.

import timeit
from math import sqrt
from matplotlib.pyplot import plot, legend, show

def factors_1(n):
    step = 2 if n%2 else 1
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))

def factors_2(n):
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0)))

X = range(1,100000,1000)
Y = []
for i in X:
    f_1 = timeit.timeit('factors_1({})'.format(i), setup='from __main__ import factors_1', number=10000)
    f_2 = timeit.timeit('factors_2({})'.format(i), setup='from __main__ import factors_2', number=10000)
    Y.append(f_1/f_2)
plot(X,Y, label='Running time with/without parity check')
legend()
show()

X = rango (1,100,1) X = rango (1,100,1)

No hay diferencia significativa aquí, pero con números más grandes, la ventaja es obvia:

X = rango (1,100000,1000) (solo números impares) X = rango (1,100000,1000) (solo números impares)

X = rango (2,100000,100) (solo números pares) X = rango (2,100000,100) (solo números pares)

X = rango (1,100000,1001) (paridad alterna) X = rango (1,100000,1001) (paridad alterna)

Steinar Lima
fuente
28

La respuesta de agf es realmente genial. Quería ver si podía reescribirlo para evitar usarlo reduce(). Esto es lo que se me ocurrió:

import itertools
flatten_iter = itertools.chain.from_iterable
def factors(n):
    return set(flatten_iter((i, n//i) 
                for i in range(1, int(n**0.5)+1) if n % i == 0))

También probé una versión que usa funciones generadoras difíciles:

def factors(n):
    return set(x for tup in ([i, n//i] 
                for i in range(1, int(n**0.5)+1) if n % i == 0) for x in tup)

Lo cronometré computando:

start = 10000000
end = start + 40000
for n in range(start, end):
    factors(n)

Lo ejecuté una vez para dejar que Python lo compilara, luego lo ejecuté bajo el comando time (1) tres veces y mantuve el mejor tiempo.

  • versión reducida: 11.58 segundos
  • versión de itertools: 11.49 segundos
  • versión complicada: 11.12 segundos

Tenga en cuenta que la versión de itertools está creando una tupla y pasándola a flatten_iter (). Si cambio el código para crear una lista, se ralentiza ligeramente:

  • versión de iterools (lista): 11.62 segundos

Creo que la versión de funciones del generador complicado es la más rápida posible en Python. Pero no es realmente mucho más rápido que la versión reducida, aproximadamente un 4% más rápido según mis mediciones.

steveha
fuente
2
podría simplificar la "versión complicada" (eliminar innecesariamente for tup in):factors = lambda n: {f for i in range(1, int(n**0.5)+1) if n % i == 0 for f in [i, n//i]}
jfs
11

Un enfoque alternativo a la respuesta de agf:

def factors(n):    
    result = set()
    for i in range(1, int(n ** 0.5) + 1):
        div, mod = divmod(n, i)
        if mod == 0:
            result |= {i, div}
    return result
Eryk Sun
fuente
1
¿Puedes explicar la parte div, mod?
Adnan
3
divmod (x, y) devuelve ((xx% y) / y, x% y), es decir, el cociente y el resto de la división.
c4757p
Esto no maneja bien los factores duplicados; pruebe 81 por ejemplo.
phkahler
Su respuesta es más clara, así que pude entenderlo lo suficiente como para malinterpretarlo. Estaba pensando en la factorización prima donde querrías llamar múltiples 3's. Esto debería estar bien, ya que eso es lo que solicitó el OP.
phkahler
Apilé todo en una línea porque la respuesta de agf lo hizo. Estaba interesado en ver si reduce()era significativamente más rápido, así que hice casi todo lo que no fuera la reduce()parte de la misma manera que agf. Para facilitar la lectura, sería bueno ver una llamada de función como en is_even(n)lugar de una expresión como n % 2 == 0.
steveha
9

Aquí hay una alternativa a la solución de @ agf que implementa el mismo algoritmo en un estilo más pitónico:

def factors(n):
    return set(
        factor for i in range(1, int(n**0.5) + 1) if n % i == 0
        for factor in (i, n//i)
    )

Esta solución funciona en Python 2 y Python 3 sin importar y es mucho más legible. No he probado el rendimiento de este enfoque, pero asintóticamente debería ser el mismo, y si el rendimiento es una preocupación seria, ninguna de las soluciones es óptima.

Julian
fuente
7

Hay un algoritmo de fuerza industrial en SymPy llamado factorint :

>>> from sympy import factorint
>>> factorint(2**70 + 3**80) 
{5: 2,
 41: 1,
 101: 1,
 181: 1,
 821: 1,
 1597: 1,
 5393: 1,
 27188665321L: 1,
 41030818561L: 1}

Esto tomó menos de un minuto. Cambia entre un cóctel de métodos. Consulte la documentación vinculada anteriormente.

Dados todos los factores primos, todos los demás factores pueden construirse fácilmente.


Tenga en cuenta que incluso si se permitió que la respuesta aceptada se ejecutara durante el tiempo suficiente (es decir, una eternidad) para factorizar el número anterior, para algunos números grandes fallará, como en el siguiente ejemplo. Esto se debe a lo descuidado int(n**0.5). Por ejemplo, cuando n = 10000000000000079**2tenemos

>>> int(n**0.5)
10000000000000078L

Como 10000000000000079 es primo , el algoritmo de la respuesta aceptada nunca encontrará este factor. Tenga en cuenta que no es solo un off-by-one; para números más grandes se desactivará por más. Por esta razón, es mejor evitar los números de coma flotante en algoritmos de este tipo.

Evgeni Sergeev
fuente
2
No encuentra todos los divisores, sino solo factores primos, por lo que no es realmente una respuesta. Debería mostrar cómo se pueden construir todos los demás factores, ¡no solo decir que es fácil! Por cierto, sympy.divisors puede ser una mejor opción para responder esta pregunta.
Colin Pitrat
Y tenga en cuenta que sympy.divisors no es mucho más rápido que la solución aceptada.
Colin Pitrat
@ColinPitrat: Dudo que sympy.divisorsno sea mucho más rápido, para números con pocos divisores en particular. ¿Tienes algún punto de referencia?
Ry-
@Ry Hice una cuando escribí este comentario hace un año. Se tarda 2 minutos en escribir uno, así que siéntase libre de verificar dos veces.
Colin Pitrat
3
@ColinPitrat: marcado. Como se esperaba, la respuesta aceptada es aproximadamente la misma velocidad que sympy.divisorspara 100,000 y más lenta para cualquier cosa más alta (cuando la velocidad realmente importa). (Y, por supuesto, sympy.divisorsfunciona en números como 10000000000000079**2.)
Ry-
7

Para n hasta 10 ** 16 (tal vez incluso un poco más), aquí hay una solución rápida y pura de Python 3.6,

from itertools import compress

def primes(n):
    """ Returns  a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def factorization(n):
    """ Returns a list of the prime factorization of n """
    pf = []
    for p in primeslist:
      if p*p > n : break
      count = 0
      while not n % p:
        n //= p
        count += 1
      if count > 0: pf.append((p, count))
    if n > 1: pf.append((n, 1))
    return pf

def divisors(n):
    """ Returns an unsorted list of the divisors of n """
    divs = [1]
    for p, e in factorization(n):
        divs += [x*p**k for k in range(1,e+1) for x in divs]
    return divs

n = 600851475143
primeslist = primes(int(n**0.5)+1) 
print(divisors(n))
Bruno Astrolino
fuente
6

Mejora adicional a la solución de afg & eryksun. El siguiente código devuelve una lista ordenada de todos los factores sin cambiar la complejidad asintótica del tiempo de ejecución:

    def factors(n):    
        l1, l2 = [], []
        for i in range(1, int(n ** 0.5) + 1):
            q,r = n//i, n%i     # Alter: divmod() fn can be used.
            if r == 0:
                l1.append(i) 
                l2.append(q)    # q's obtained are decreasing.
        if l1[-1] == l2[-1]:    # To avoid duplication of the possible factor sqrt(n)
            l1.pop()
        l2.reverse()
        return l1 + l2

Idea: en lugar de usar la función list.sort () para obtener una lista ordenada que da complejidad a nlog (n); Es mucho más rápido usar list.reverse () en l2 que requiere complejidad O (n). (Así es como se hace python). Después de l2.reverse (), l2 puede agregarse a l1 para obtener la lista ordenada de factores.

Tenga en cuenta que l1 contiene i -s que están aumentando. l2 contiene q -s que están disminuyendo. Esa es la razón detrás del uso de la idea anterior.

Pranjal Mittal
fuente
Bastante seguro list.reversees O (n) no O (1), no es que cambie la complejidad general.
agf
Si, eso es correcto. Cometí un error. Debería ser O (n). (He actualizado la respuesta ahora a la correcta)
Pranjal Mittal
Es aproximadamente 2 veces más lento que las soluciones de @ steveha o @ agf.
jfs
Puede obtener una pequeña mejora de velocidad (2-3%) volviendo en l1 + l2.reversed()lugar de invertir la lista en su lugar.
Rakurai
6

He intentado la mayoría de estas maravillosas respuestas con tiempo para comparar su eficiencia con mi función simple y, sin embargo, veo constantemente que la mía supera a las que se enumeran aquí. Pensé en compartirlo y ver qué piensan ustedes.

def factors(n):
    results = set()
    for i in xrange(1, int(math.sqrt(n)) + 1):
        if n % i == 0:
            results.add(i)
            results.add(int(n/i))
    return results

Como está escrito, tendrá que importar matemáticas para probar, pero reemplazar math.sqrt (n) con n **. 5 debería funcionar igual de bien. No me molesto en perder el tiempo buscando duplicados porque los duplicados no pueden existir en un conjunto independientemente.

oxrock
fuente
¡Buena cosa! Si coloca int (math.sqrt (n)) + 1 fuera del ciclo for, debería obtener un poco más de rendimiento ya que no tendrá que volver a calcularlo cada iteración del ciclo for
Tristan Forward
3
@TristanForward: no es así como funcionan los bucles en Python. xrange(1, int(math.sqrt(n)) + 1)se evalúa una vez
Ry-
5

Aquí hay otra alternativa sin reducción que funciona bien con grandes números. Se utiliza sumpara aplanar la lista.

def factors(n):
    return set(sum([[i, n//i] for i in xrange(1, int(n**0.5)+1) if not n%i], []))
dansalmo
fuente
1
Esto no es así, es tiempo innecesariamente cuadrático. No use sumni reduce(list.__add__)para aplanar una lista.
juanpa.arrivillaga
4

Asegúrese de obtener el número más grande que sqrt(number_to_factor)para números inusuales como 99 que tiene 3 * 3 * 11 y floor sqrt(99)+1 == 10.

import math

def factor(x):
  if x == 0 or x == 1:
    return None
  res = []
  for i in range(2,int(math.floor(math.sqrt(x)+1))):
    while x % i == 0:
      x /= i
      res.append(i)
  if x != 1: # Unusual numbers
    res.append(x)
  return res
Mbowden
fuente
1
No produce todos los factores de un número. Calcula los factores primos de un número, por ejemplo, para lo x=8esperado:, [1, 2, 4, 8]obtenido:[2, 2, 2]
jfs
11 se encuentra cuando 9 se completa en el código proporcionado por @agf. `i = 9 -> 99% 9 == 0 -> 9 y 99/9 = 11 se agrega.
Steinar Lima
4

La forma más simple de encontrar factores de un número:

def factors(x):
    return [i for i in range(1,x+1) if x%i==0]
GooDeeJaY
fuente
2

Aquí hay un ejemplo si desea utilizar el número primos para ir mucho más rápido. Estas listas son fáciles de encontrar en Internet. Agregué comentarios en el código.

# http://primes.utm.edu/lists/small/10000.txt
# First 10000 primes

_PRIMES = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 
        31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 
        73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 
        127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 
        179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 
        233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 
        283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 
        353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 
        419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 
        467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 
        547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 
        607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 
        661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 
        739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 
        811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 
        877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 
        947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 
# Mising a lot of primes for the purpose of the example
)


from bisect import bisect_left as _bisect_left
from math import sqrt as _sqrt


def get_factors(n):
    assert isinstance(n, int), "n must be an integer."
    assert n > 0, "n must be greather than zero."
    limit = pow(_PRIMES[-1], 2)
    assert n <= limit, "n is greather then the limit of {0}".format(limit)
    result = set((1, n))
    root = int(_sqrt(n))
    primes = [t for t in get_primes_smaller_than(root + 1) if not n % t]
    result.update(primes)  # Add all the primes factors less or equal to root square
    for t in primes:
        result.update(get_factors(n/t))  # Add all the factors associted for the primes by using the same process
    return sorted(result)


def get_primes_smaller_than(n):
    return _PRIMES[:_bisect_left(_PRIMES, n)]
Pierre Thibault
fuente
Creé un proyecto en Github: github.com/Pierre-Thibault/Factor .
Pierre Thibault
2

un algoritmo potencialmente más eficiente que los presentados aquí ya (especialmente si hay pequeños factores primos en n). El truco aquí es ajustar el límite hasta el cual se necesita la división de prueba cada vez que se encuentran factores primos:

def factors(n):
    '''
    return prime factors and multiplicity of n
    n = p0^e0 * p1^e1 * ... * pk^ek encoded as
    res = [(p0, e0), (p1, e1), ..., (pk, ek)]
    '''

    res = []

    # get rid of all the factors of 2 using bit shifts
    mult = 0
    while not n & 1:
        mult += 1
        n >>= 1
    if mult != 0:
        res.append((2, mult))

    limit = round(sqrt(n))
    test_prime = 3
    while test_prime <= limit:
        mult = 0
        while n % test_prime == 0:
            mult += 1
            n //= test_prime
        if mult != 0:
            res.append((test_prime, mult))
            if n == 1:              # only useful if ek >= 3 (ek: multiplicity
                break               # of the last prime) 
            limit = round(sqrt(n))  # adjust the limit
        test_prime += 2             # will often not be prime...
    if n != 1:
        res.append((n, 1))
    return res

Esto, por supuesto, sigue siendo una división de prueba y nada más elegante. y, por lo tanto, sigue siendo muy limitada en su eficiencia (especialmente para grandes números sin pequeños divisores).

esto es python3; la división //debería ser lo único que necesita adaptar para python 2 (agregar from __future__ import division).

protagonista de hiro
fuente
1

El uso set(...)hace que el código sea un poco más lento, y solo es realmente necesario cuando se verifica la raíz cuadrada. Aquí está mi versión:

def factors(num):
    if (num == 1 or num == 0):
        return []
    f = [1]
    sq = int(math.sqrt(num))
    for i in range(2, sq):
        if num % i == 0:
            f.append(i)
            f.append(num/i)
    if sq > 1 and num % sq == 0:
        f.append(sq)
        if sq*sq != num:
            f.append(num/sq)
    return f

La if sq*sq != num:condición es necesaria para números como 12, donde la raíz cuadrada no es un número entero, pero el piso de la raíz cuadrada es un factor.

Tenga en cuenta que esta versión no devuelve el número en sí, pero eso es una solución fácil si lo desea. La salida tampoco está ordenada.

Lo cronometré corriendo 10000 veces en todos los números 1-200 y 100 veces en todos los números 1-5000. Supera a todas las otras versiones que probé, incluidas las soluciones de dansalmo, Jason Schorn, oxrock, agf, steveha y eryksun, aunque la de oxrock es, con mucho, la más cercana.

HamsterBoo
fuente
1

su factor máximo no es más que su número, entonces, digamos

def factors(n):
    factors = []
    for i in range(1, n//2+1):
        if n % i == 0:
            factors.append (i)
    factors.append(n)

    return factors

voilá!

Polina Novikova
fuente
1
 import math

    '''
    I applied finding prime factorization to solve this. (Trial Division)
    It's not complicated
    '''


    def generate_factors(n):
        lower_bound_check = int(math.sqrt(n))  # determine lowest bound divisor range [16 = 4]
        factors = set()  # store factors
        for divisors in range(1, lower_bound_check + 1):  # loop [1 .. 4]
            if n % divisors == 0:
                factors.add(divisors)  # lower bound divisor is found 16 [ 1, 2, 4]
                factors.add(n // divisors)  # get upper divisor from lower [ 16 / 1 = 16, 16 / 2 = 8, 16 / 4 = 4]
        return factors  # [1, 2, 4, 8 16]


    print(generate_factors(12)) # {1, 2, 3, 4, 6, 12} -> pycharm output

 Pierre Vriens hopefully this makes more sense. this is an O(nlogn) solution. 
Tangang Atanga
fuente
0

Use algo tan simple como la siguiente lista de comprensión, y observe que no necesitamos probar 1 y el número que estamos tratando de encontrar:

def factors(n):
    return [x for x in range(2, n//2+1) if n%x == 0]

En referencia al uso de la raíz cuadrada, digamos que queremos encontrar factores de 10. La porción entera del sqrt(10) = 4por lo tanto range(1, int(sqrt(10))) = [1, 2, 3, 4]y probar hasta 4 claramente falla 5.

A menos que me falte algo que sugeriría, si debe hacerlo de esta manera, usando int(ceil(sqrt(x))). Por supuesto, esto produce muchas llamadas innecesarias a las funciones.

Jason Schorn
fuente
El problema con esta solución es que verifica muchos números que posiblemente no pueden ser factores, y verifica el más alto de cada par de factores por separado cuando ya sabe que es un factor después de encontrar el más pequeño del par de factores.
agf
1
@JasonSchorn: Cuando encuentre 2, inmediatamente sabrá que 10/2 = 5 también es un divisor, ¡no es necesario verificar 5 por separado! :)
Moberg
0

Creo que la solución de legibilidad y velocidad de @ oxrock es la mejor, así que aquí está el código reescrito para python 3+:

def num_factors(n):
    results = set()
    for i in range(1, int(n**0.5) + 1):
        if n % i == 0: results.update([i,int(n/i)])
    return results
Nic Scozzaro
fuente
0

Me sorprendió bastante cuando vi esta pregunta que nadie usaba numpy incluso cuando numpy es mucho más rápido que los bucles de pitón. Al implementar la solución de @ agf con numpy y resultó en promedio 8 veces más rápido . Creo que si implementaras algunas de las otras soluciones en numpy, podrías obtener momentos increíbles.

Aquí está mi función:

import numpy as np
def b(n):
    r = np.arange(1, int(n ** 0.5) + 1)
    x = r[np.mod(n, r) == 0]
    return set(np.concatenate((x, n / x), axis=None))   

Observe que los números del eje x no son la entrada a las funciones. La entrada a las funciones es 2 al número en el eje x menos 1. Entonces, donde diez es la entrada sería 2 ** 10-1 = 1023

Resultados de la prueba de rendimiento de usar numpy en lugar de for loops.

Benedikt Vilji Magnússon
fuente
1
Si va a utilizar una biblioteca, también puede convertirla en la correcta: SymPy, como se ve en la respuesta de Evgeni Sergeev.
Ry-
0
import 'dart:math';
generateFactorsOfN(N){
  //determine lowest bound divisor range
  final lowerBoundCheck = sqrt(N).toInt();
  var factors = Set<int>(); //stores factors
  /**
   * Lets take 16:
   * 4 = sqrt(16)
   * start from 1 ...  4 inclusive
   * check mod 16 % 1 == 0?  set[1, (16 / 1)]
   * check mod 16 % 2 == 0?  set[1, (16 / 1) , 2 , (16 / 2)]
   * check mod 16 % 3 == 0?  set[1, (16 / 1) , 2 , (16 / 2)] -> unchanged
   * check mod 16 % 4 == 0?  set[1, (16 / 1) , 2 , (16 / 2), 4, (16 / 4)]
   *
   *  ******************* set is used to remove duplicate
   *  ******************* case 4 and (16 / 4) both equal to 4
   *  return factor set<int>.. this isn't ordered
   */

  for(var divisor = 1; divisor <= lowerBoundCheck; divisor++){
    if(N % divisor == 0){
      factors.add(divisor);
      factors.add(N ~/ divisor); // ~/ integer division 
    }
  }
  return factors;
}
Tangang Atanga
fuente
Casi todo el algoritmo aquí se limita al rango del número * .5, pero en realidad ese rango es mucho más pequeño. en realidad es sqrt del número. Si tenemos el divisor inferior, podemos obtener el divisor superior fácilmente. ya que es solo el número / divisor. para 16 obtengo 4 para el sqrt, luego hago un bucle de 1 a 4. dado que 2 es un divisor de límite inferior de 16, tomamos 16/2 para obtener 8. si tenemos 1, entonces para obtener 16 es (16/1). Se me ocurrió esto mientras aprendía sobre la factorización prima, así que no sé si se publica en otro lugar, pero funciona incluso para grandes cantidades. Puedo proporcionar una solución de Python.
Tangang Atanga
-4

Creo que esta es la forma más sencilla de hacerlo:

    x = 23

    i = 1
    while i <= x:
      if x % i == 0:
        print("factor: %s"% i)
      i += 1
DeDude
fuente
Su respuesta, si bien da el resultado correcto, es muy ineficiente. Echa un vistazo a la respuesta aceptada. Una explicación de cómo resuelve el problema siempre ayuda a que la respuesta sea más útil.
Nick