Qual è il modo più efficiente di trovare tutti i fattori di un numero in Python?


142

Qualcuno può spiegarmi un modo efficace di trovare tutti i fattori di un numero in Python (2.7)?

Posso creare un algoritmo per farlo, ma penso che sia scarsamente codificato e impieghi troppo tempo a produrre un risultato per un numero elevato.


3
Non conosco Python. Ma questa pagina potrebbe essere utile per te en.wikipedia.org/wiki/Integer_factorization
Stan

3
Che ne dici di usare primefac? pypi.python.org/pypi/primefac
Zubo

Risposte:


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)))

Ciò restituirà tutti i fattori, molto rapidamente, di un numero n.

Perché radice quadrata come limite superiore?

sqrt(x) * sqrt(x) = x. Quindi, se i due fattori sono uguali, sono entrambi la radice quadrata. Se ingrandisci un fattore, devi ridurre l'altro fattore. Ciò significa che uno dei due sarà sempre inferiore o uguale a sqrt(x), quindi devi solo cercare fino a quel punto per trovare uno dei due fattori corrispondenti. È quindi possibile utilizzare x / fac1per ottenere fac2.

Sta reduce(list.__add__, ...)prendendo le piccole liste [fac1, fac2]e le unisce in una lunga lista.

I [i, n/i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0rendimenti una coppia di fattori se il resto quando si divide ndal minore è zero (non ha bisogno controlla la più grande anche; si ottiene solo che dividendo ndal minore.)

L' set(...)esterno si sta sbarazzando dei duplicati, il che accade solo per quadrati perfetti. Perché n = 4, questo tornerà 2due volte, quindi setsbarazzarsi di uno di loro.


1
Ho copiato e incollato questo da un elenco di algoritmi sul mio computer, tutto ciò che ho fatto è stato incapsulare il sqrt- è probabilmente da prima che la gente stesse davvero pensando di supportare Python 3. Penso che il sito in cui l'ho preso lo abbia provato __iadd__e che fosse più veloce . Mi sembra di ricordare qualcosa x**0.5sull'essere più veloce che sqrt(x)ad un certo punto - ed è più infallibile in quel modo.
AGF

7
Sembra di eseguire il 15% più veloce se uso if not n % iinvece diif n % i == 0
dansalmo l'

3
@sthzg Vogliamo che restituisca un numero intero, non un float, e su Python 3 /restituirà un float anche se entrambi gli argomenti sono numeri interi e sono esattamente divisibili, ovvero 4 / 2 == 2.0no 2.
AGF

7
So che questa è una vecchia domanda, ma in Python 3.x è necessario aggiungere from functools import reduceper farlo funzionare.
anonymoose,

5
@unseen_rider: non suona bene. Potete fornire qualcosa per il backup?
Ry-

55

La soluzione presentata da @agf è eccezionale, ma si può ottenere un tempo di esecuzione più veloce del 50% per un numero dispari arbitrario verificando la parità. Poiché i fattori di un numero dispari sono sempre dispari, non è necessario verificarli quando si tratta di numeri dispari.

Ho appena iniziato a risolvere Project Euler solo i puzzle di . In alcuni problemi, un controllo del divisore viene chiamato all'interno di due forloop nidificati e l'esecuzione di questa funzione è quindi essenziale.

Combinando questo fatto con l'eccellente soluzione di agf, ho finito con questa funzione:

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)))

Tuttavia, su piccoli numeri (~ <100), l'overhead aggiuntivo di questa modifica potrebbe richiedere più tempo alla funzione.

Ho eseguito alcuni test per verificare la velocità. Di seguito è riportato il codice utilizzato. Per produrre i diversi grafici, ho modificato di X = range(1,100,1)conseguenza.

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 = intervallo (1.100,1) X = intervallo (1.100,1)

Nessuna differenza significativa qui, ma con numeri più grandi, il vantaggio è evidente:

X = intervallo (1.100000.1000) (solo numeri dispari) X = intervallo (1.100000.1000) (solo numeri dispari)

X = intervallo (2.100000.100) (solo numeri pari) X = intervallo (2.100000.100) (solo numeri pari)

X = intervallo (1.100000.1001) (parità alternata) X = intervallo (1.100000.1001) (parità alternata)


28

la risposta di agf è davvero piuttosto interessante. Volevo vedere se potevo riscriverlo per evitare di usarlo reduce(). Questo è quello che mi è venuto in mente:

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))

Ho anche provato una versione che utilizza funzioni del generatore complicate:

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)

L'ho cronometrato calcolando:

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

L'ho eseguito una volta per consentire a Python di compilarlo, quindi l'ho eseguito con il comando time (1) tre volte e ho mantenuto il momento migliore.

  • ridurre la versione: 11,58 secondi
  • versione itertools: 11,49 secondi
  • versione difficile: 11.12 secondi

Nota che la versione itertools sta costruendo una tupla e la sta passando a flatten_iter (). Se cambio invece il codice per creare un elenco, questo rallenta leggermente:

  • versione iterools (elenco): 11,62 secondi

Credo che la delicata versione delle funzioni del generatore sia la più veloce possibile in Python. Ma non è molto più veloce della versione ridotta, circa il 4% più veloce in base alle mie misurazioni.


2
potresti semplificare la "versione complicata" (rimuovi inutili 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 il

11

Un approccio alternativo alla risposta di 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

1
Puoi spiegare la parte div, mod?
Adnan,

3
divmod (x, y) restituisce ((xx% y) / y, x% y), ovvero il quoziente e il resto della divisione.
c4757p,

Questo non gestisce bene i fattori duplicati - prova 81 ad esempio.
Phkahler,

La tua risposta è più chiara, quindi sono stato in grado di farlo solo per capire male. Stavo pensando alla scomposizione in fattori primi dove avresti voluto chiamare più 3. Questo dovrebbe andare bene, poiché è quello che l'OP ha richiesto.
Phkahler,

Ho ammucchiato tutto in una riga perché la risposta di agf lo ha fatto. Ero interessato a vedere se reduce()era significativamente più veloce, quindi ho fatto praticamente tutto tranne la reduce()parte allo stesso modo. Per leggibilità, sarebbe bello vedere una funzione chiamata is_even(n)piuttosto che un'espressione simile n % 2 == 0.
steveha,

9

Ecco un'alternativa alla soluzione di @ agf che implementa lo stesso algoritmo in uno stile più pitonico:

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)
    )

Questa soluzione funziona in Python 2 e Python 3 senza importazioni ed è molto più leggibile. Non ho testato le prestazioni di questo approccio, ma asintoticamente dovrebbe essere lo stesso e se le prestazioni sono un problema serio, nessuna delle due soluzioni è ottimale.


7

In SymPy esiste un algoritmo di forza del settore chiamato 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}

Ciò ha richiesto meno di un minuto. Passa da un cocktail di metodi. Vedi la documentazione collegata sopra.

Dati tutti i fattori primi, tutti gli altri fattori possono essere costruiti facilmente.


Si noti che anche se la risposta accettata è stata eseguita per un tempo sufficientemente lungo (cioè un'eternità) da fattorizzare il numero sopra, per alcuni numeri di grandi dimensioni fallirà, come nell'esempio seguente. Ciò è dovuto allo sciatto int(n**0.5). Ad esempio, quando n = 10000000000000079**2, abbiamo

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

Poiché 10000000000000079 è un numero primo , l'algoritmo della risposta accettata non troverà mai questo fattore. Si noti che non è solo un off-by-one; per numeri più grandi sarà disattivato da più. Per questo motivo è meglio evitare i numeri in virgola mobile negli algoritmi di questo tipo.


2
Non trova tutti i divisori ma solo i fattori primi, quindi non è davvero una risposta. Dovresti mostrare come tutti gli altri fattori possono essere costruiti, non solo dire che è facile! A proposito, sympy.divisors potrebbe essere una corrispondenza migliore per rispondere a questa domanda.
Colin Pitrat,

E nota che sympy.divisors non è molto più veloce della soluzione accettata.
Colin Pitrat,

@ColinPitrat: dubito che sympy.divisorsnon sia molto più veloce, in particolare per i numeri con pochi divisori. Hai dei benchmark?
Ry-

@Ry ne ho fatto uno quando ho scritto questo commento un anno fa. Ci vogliono 2 minuti per scriverne uno, quindi sentiti libero di ricontrollare.
Colin Pitrat,

3
@ColinPitrat: selezionato. Come previsto, la risposta accettata è circa la stessa velocità sympy.divisorsdi 100.000 e più lenta per qualsiasi valore superiore (quando la velocità conta davvero). (E, naturalmente, sympy.divisorsfunziona su numeri come 10000000000000079**2.)
Ry-

7

Per n fino a 10 ** 16 (forse anche un po 'di più), ecco una soluzione Python 3.6 veloce e pura,

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))

6

Ulteriore miglioramento della soluzione di afg & eryksun. Il seguente pezzo di codice restituisce un elenco ordinato di tutti i fattori senza modificare la complessità asintotica del runtime:

    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: Invece di usare la funzione list.sort () per ottenere un elenco ordinato che dà complessità a nlog (n); È molto più veloce usare list.reverse () su l2 che richiede complessità O (n). (Ecco come viene creato Python.) Dopo l2.reverse (), l2 può essere aggiunto a l1 per ottenere l'elenco ordinato dei fattori.

Nota, l1 contiene i -s che stanno aumentando. l2 contiene q -s che stanno diminuendo. Questo è il motivo dietro l'utilizzo dell'idea sopra.


Abbastanza sicuro list.reverseè O (n) non O (1), non che cambia la complessità complessiva.
1313

Sì, è giusto. Ho fatto un errore. Dovrebbe essere O (n). (Ho aggiornato la risposta ora a quella corretta)
Pranjal Mittal,

È circa 2 volte più lento delle soluzioni di @ steveha o @ agf.
jfs,

Puoi ottenere un piccolo (2-3%) miglioramento della velocità ritornando l1 + l2.reversed()anziché invertire l'elenco in atto.
Rakurai,

6

Ho provato la maggior parte di queste meravigliose risposte con il tempo a confrontare la loro efficienza rispetto alla mia semplice funzione e tuttavia vedo costantemente le mie sovraperformare quelle elencate qui. Ho pensato di condividerlo e vedere cosa ne pensate tutti.

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

Come è scritto, dovrai importare la matematica per testare, ma sostituire math.sqrt (n) con n **. 5 dovrebbe funzionare altrettanto bene. Non mi preoccupo di perdere tempo a controllare i duplicati perché i duplicati non possono esistere in un set a prescindere.


Roba fantastica! Se si inserisce int (math.sqrt (n)) + 1 al di fuori del ciclo for, si dovrebbe ottenere un po 'più prestazioni da esso poiché non sarà necessario ricalcolarlo ogni iterazione del ciclo for
Tristan Forward

3
@TristanForward: Non è così che funzionano i loop in Python. xrange(1, int(math.sqrt(n)) + 1)viene valutato una volta.
Ry-

5

Ecco un'altra alternativa senza riduzioni che si comporta bene con grandi numeri. Usa sumper appiattire l'elenco.

def factors(n):
    return set(sum([[i, n//i] for i in xrange(1, int(n**0.5)+1) if not n%i], []))

1
Questo no, è un tempo inutilmente quadratico. Non utilizzare sumo reduce(list.__add__)per appiattire un elenco.
juanpa.arrivillaga,

4

Assicurati di prendere il numero più grande rispetto sqrt(number_to_factor)a numeri insoliti come 99 che ha 3 * 3 * 11 e 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

1
Non produce tutti i fattori di un numero. Calcola i fattori primi di un numero, ad esempio, per il x=8previsto[1, 2, 4, 8][2, 2, 2]
:,

11 viene trovato quando 9 viene inserito nel codice fornito da @agf. `i = 9 -> 99% 9 == 0 -> 9 e 99/9 = 11 è aggiunto.
Steinar Lima,

4

Il modo più semplice per trovare i fattori di un numero:

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

2

Ecco un esempio se vuoi usare il numero dei numeri primi per andare molto più veloce. Questi elenchi sono facili da trovare su Internet. Ho aggiunto commenti nel codice.

# 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)]

Ho creato un progetto su Github: github.com/Pierre-Thibault/Factor .
Pierre Thibault,

2

un algoritmo potenzialmente più efficiente di quelli già presentati qui (specialmente se ci sono piccoli facton primi in n). il trucco qui è di adattare il limite a cui è necessaria la divisione di prova ogni volta che vengono trovati i fattori primi:

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

questa ovviamente è ancora divisione di prova e niente di più elegante. e quindi ancora molto limitato nella sua efficienza (specialmente per grandi numeri senza piccoli divisori).

questo è python3; la divisione //dovrebbe essere l'unica cosa che devi adattare per Python 2 (aggiungi from __future__ import division).


1

L'uso set(...)rende il codice leggermente più lento ed è veramente necessario solo quando si controlla la radice quadrata. Ecco la mia versione:

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:condizione è necessaria per numeri come 12, in cui la radice quadrata non è un numero intero, ma il pavimento della radice quadrata è un fattore.

Nota che questa versione non restituisce il numero stesso, ma è una soluzione semplice se lo desideri. Anche l'output non è ordinato.

L'ho cronometrato correndo 10000 volte su tutti i numeri 1-200 e 100 volte su tutti i numeri 1-5000. Supera tutte le altre versioni che ho testato, comprese le soluzioni di dansalmo, Jason Schorn, oxrock, agf, steveha e eryksun, sebbene quelle di oxrock siano di gran lunga le più vicine.


1

il tuo fattore massimo non è superiore al tuo numero, quindi, diciamo

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

    return factors

Ecco!


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. 

0

Usa qualcosa di semplice come la seguente comprensione dell'elenco, notando che non abbiamo bisogno di testare 1 e il numero che stiamo cercando di trovare:

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

In riferimento all'uso della radice quadrata, diciamo che vogliamo trovare fattori di 10. La parte intera del sqrt(10) = 4pertanto range(1, int(sqrt(10))) = [1, 2, 3, 4]e testare fino a 4 manca chiaramente 5.

A meno che non mi manchi qualcosa che suggerirei, se devi farlo in questo modo, usando int(ceil(sqrt(x))). Naturalmente questo produce molte chiamate non necessarie alle funzioni.


Il problema con questa soluzione è che controlla molti numeri che non possono essere fattori - e controlla il più alto di ciascuna coppia di fattori separatamente quando sai già che è un fattore dopo aver trovato il più piccolo della coppia di fattori.
1313

1
@JasonSchorn: quando trovi 2, sai immediatamente che anche 10/2 = 5 è un divisore, non è necessario controllare 5 separatamente! :)
Moberg,

0

Penso che per la leggibilità e la soluzione di speed @ oxrock sia la migliore, quindi ecco il codice riscritto per 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

0

Sono stato piuttosto sorpreso quando ho visto questa domanda che nessuno ha usato il numpy anche quando il numpy è molto più veloce dei loop in pitone. Implementando la soluzione di @ agf con numpy, si è rivelato in media 8 volte più veloce . Credo che se tu avessi implementato alcune delle altre soluzioni in modo intorpidito, potresti ottenere tempi incredibili.

Ecco la mia funzione:

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))   

Si noti che i numeri dell'asse x non sono l'input per le funzioni. L'ingresso alle funzioni è 2 rispetto al numero sull'asse x meno 1. Quindi dove dieci è l'ingresso sarebbe 2 ** 10-1 = 1023

Risultati del test delle prestazioni sull'utilizzo di numpy anziché per i loop.


1
Se hai intenzione di utilizzare una libreria, puoi anche renderla quella giusta: SymPy, come si vede nella risposta di 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;
}

Quasi tutti gli algoritmi qui limitano l'intervallo al numero * .5, ma in realtà quell'intervallo è molto più piccolo. è effettivamente sqrt del numero. se abbiamo il divisore inferiore possiamo ottenerlo facilmente. dal momento che è solo il numero / divisore. per 16 ottengo 4 per il sqrt, quindi ciclo da 1 a 4. poiché 2 è un divisore limite inferiore di 16 prendiamo 16/2 per ottenere 8. se abbiamo 1, allora per ottenere 16 è (16/1). Mi è venuto in mente mentre imparavo la fattorizzazione primaria, quindi non so se è pubblicato altrove, ma funziona anche per grandi numeri. Sono in grado di fornire una soluzione Python.
Tangang Atanga,

-4

Suppongo che questo sia il modo più semplice per farlo:

    x = 23

    i = 1
    while i <= x:
      if x % i == 0:
        print("factor: %s"% i)
      i += 1

La tua risposta, pur dando il giusto risultato, è molto inefficiente. Dai un'occhiata alla risposta accettata. Una spiegazione di come risolve il problema aiuta sempre una risposta a essere più utile.
Nick,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.