Qual seria o algoritmo mais ideal (em termos de desempenho) para calcular o número de divisores de um determinado número?
Seria ótimo se você pudesse fornecer pseudocódigo ou um link para algum exemplo.
EDIT: Todas as respostas foram muito úteis, obrigado. Estou implementando a peneira de Atkin e depois vou usar algo semelhante ao que Jonathan Leffler indicou. O link postado por Justin Bozonier tem mais informações sobre o que eu queria.
performance
algorithm
pseudocode
esquiador
fonte
fonte
Respostas:
Dmitriy está certo de que você desejará que a Peneira de Atkin gere a lista principal, mas não creio que isso cuide de toda a questão. Agora que você tem uma lista de números primos, precisará ver quantos desses números atuam como divisores (e com que frequência).
Aqui está um pouco de python para o algo.Olhe aqui e pesquise "Subject: math - need divisors algoritm". Apenas conte o número de itens na lista, em vez de devolvê-los.Aqui está um Dr.Math que explica exatamente o que você precisa fazer matematicamente.
Essencialmente, tudo se resume a se o seu número
n
é:n = a^x * b^y * c^z
(onde a, bec são os divisores primos de n e x, ye z são o número de vezes que o divisor é repetido), a contagem total de todos os divisores é:
(x + 1) * (y + 1) * (z + 1)
.Edit: BTW, para encontrar a, b, c, etc, você vai querer fazer o que equivale a algo ganancioso se eu estiver entendendo isso corretamente. Comece com o seu maior divisor principal e multiplique-o sozinho até que uma multiplicação adicional exceda o número n. Em seguida, vá para o próximo fator mais baixo e multiplique o número primo anterior ^ número de vezes que foi multiplicado pelo número primo atual e continue multiplicando pelo número primo até que o próximo exceda n ... etc. Acompanhe o número de vezes que você multiplica o número primo. divisores juntos e aplique esses números na fórmula acima.
Não tenho 100% de certeza da minha descrição de algo, mas se não for, é algo semelhante.
fonte
n = (a^x * b^y * c^z)-(x + 1) * (y + 1) * (z + 1)
é a regra #Existem muito mais técnicas de factoring do que a peneira de Atkin. Por exemplo, suponha que desejamos fatorar 5893. Bem, seu sqrt é 76,76 ... Agora, tentaremos escrever 5893 como um produto de quadrados. Bem (77 * 77 - 5893) = 36, que é 6 ao quadrado, então 5893 = 77 * 77 - 6 * 6 = (77 + 6) (77-6) = 83 * 71. Se isso não tivesse funcionado, teríamos analisado se 78 * 78 - 5893 era um quadrado perfeito. E assim por diante. Com essa técnica, você pode testar rapidamente fatores próximos à raiz quadrada de n muito mais rapidamente do que testando primos individuais. Se você combinar essa técnica para excluir primos grandes com uma peneira, terá um método de fatoração muito melhor do que apenas com a peneira.
E essa é apenas uma das muitas técnicas desenvolvidas. Este é bastante simples. Você levaria muito tempo para aprender, digamos, a teoria dos números suficiente para entender as técnicas de fatoração baseadas em curvas elípticas. (Eu sei que eles existem. Eu não os entendo.)
Portanto, a menos que você esteja lidando com números inteiros pequenos, eu não tentaria resolver esse problema sozinho. Em vez disso, tentaria encontrar uma maneira de usar algo como a biblioteca PARI que já possui uma solução altamente eficiente implementada. Com isso, eu posso fatorar um número aleatório de 40 dígitos como 124321342332143213122323434312213424231341 em cerca de 0,05 segundos. (Sua fatoração, no caso de você ter se perguntado, é 29 * 439 * 1321 * 157907 * 284749 * 33843676813 * 4857795469949. Estou bastante confiante de que não descobriu isso usando a peneira de Atkin ...)
fonte
@Yasky
Sua função de divisores possui um erro, pois não funciona corretamente para quadrados perfeitos.
Experimentar:
fonte
Discordo que a peneira de Atkin é o caminho a percorrer, porque poderia facilmente levar mais tempo para verificar todos os números em [1, n] quanto à primalidade do que reduzir o número por divisões.
Aqui está um código que, embora um pouco mais hackeado, geralmente é muito mais rápido:
ps Esse código de python está funcionando para resolver esse problema.
fonte
Aqui está um algoritmo O (sqrt (n)) direto. Eu usei isso para resolver o projeto euler
fonte
Essa pergunta interessante é muito mais difícil do que parece e não foi respondida. A questão pode ser fatorada em duas questões muito diferentes.
1 dado N, encontre a lista L dos principais fatores de N
2 dado L, calcule o número de combinações únicas
Todas as respostas que vejo até agora se referem ao número 1 e não mencionam que não é tratável por números enormes. Para N de tamanho médio, até números de 64 bits, é fácil; para N enorme, o problema de fatoração pode demorar "para sempre". A criptografia de chave pública depende disso.
A pergunta 2 precisa de mais discussão. Se L contiver apenas números únicos, é um cálculo simples usando a fórmula de combinação para escolher k objetos de n itens. Na verdade, você precisa somar os resultados da aplicação da fórmula enquanto varia k de 1 a sizeof (L). No entanto, L normalmente conterá várias ocorrências de múltiplos números primos. Por exemplo, L = {2,2,2,3,3,5} é a fatoração de N = 360. Agora esse problema é bastante difícil!
Reajustando o item 2, dada a coleção C que contém itens k, de modo que o item a possui a 'duplicatas e o item b possui b' duplicatas, etc. Por exemplo, {2}, {2,2}, {2,2,2}, {2,3}, {2,2,3,3} devem ocorrer uma vez e apenas uma vez se L = {2,2 2,3,3,5}. Cada uma dessas sub-coleções exclusivas é um divisor exclusivo de N multiplicando os itens da sub-coleção.
fonte
p_i
é um fator primo de um número comk_i
multiplicidade, o número total de divisores desse número é(k_1+1)*(k_2+1)*...*(k_n+1)
. Acho que você já sabe disso, mas escrevo isso para o benefício de um leitor aleatório aqui.Uma resposta para sua pergunta depende muito do tamanho do número inteiro. Os métodos para números pequenos, por exemplo, menos de 100 bits e para números ~ 1000 bits (como os usados em criptografia) são completamente diferentes.
visão geral: http://en.wikipedia.org/wiki/Divisor_function
valores para pequenas
n
e algumas referências úteis: A000005: d (n) (também chamado tau (n) ou sigma_0 (n)), o número de divisores de n.exemplo do mundo real: fatoração de números inteiros
fonte
APENAS uma linha
Pensei com muito cuidado na sua pergunta e tentei escrever um código altamente eficiente e com bom desempenho. Para imprimir todos os divisores de um determinado número na tela, precisamos de apenas uma linha de código! (use a opção -std = c99 durante a compilação via gcc)
para encontrar números de divisores, você pode usar a seguinte função muito, muito rápida (funciona corretamente para todos os números inteiros, exceto 1 e 2)
ou se você tratar o número fornecido como um divisor (funcione corretamente para todo o número inteiro, exceto 1 e 2)
NOTA: as duas funções acima funcionam corretamente para todos os números inteiros positivos, exceto os números 1 e 2, portanto, são funcionais para todos os números maiores que 2, mas se você precisar cobrir 1 e 2, poderá usar uma das seguintes funções (um pouco Mais devagar)
OU
Pequeno é bonito :)
fonte
A peneira de Atkin é uma versão otimizada da peneira de Eratóstenes, que fornece todos os números primos até um determinado número inteiro. Você deve pesquisar isso no Google para obter mais detalhes.
Depois de ter essa lista, é simples dividir seu número por cada primo para ver se é um divisor exato (ou seja, o restante é zero).
As etapas básicas do cálculo dos divisores para um número (n) são [este é um pseudocódigo convertido do código real, então espero não ter introduzido erros]:
fonte
Você pode tentar este. É um pouco tolo, mas é razoavelmente rápido.
fonte
Depois de ter a fatoração principal, há uma maneira de encontrar o número de divisores. Adicione um a cada um dos expoentes em cada fator individual e multiplique os expoentes juntos.
Por exemplo: 36 Fatoração primária: 2 ^ 2 * 3 ^ 2 Divisores: 1, 2, 3, 4, 6, 9, 12, 18, 36 Número de divisores: 9
Adicione um a cada expoente 2 ^ 3 * 3 ^ 3 Multiplique expoentes: 3 * 3 = 9
fonte
Antes de se comprometer com uma solução, considere que a abordagem da peneira pode não ser uma boa resposta no caso típico.
Um tempo atrás, havia uma pergunta principal e eu fiz um teste de tempo - para números inteiros de 32 bits, pelo menos, determinar se era primo era mais lento que a força bruta. Existem dois fatores:
1) Enquanto um humano leva um tempo para fazer uma divisão, ele é muito rápido no computador - semelhante ao custo de procurar a resposta.
2) Se você não possui uma tabela principal, pode fazer um loop que é executado inteiramente no cache L1. Isso torna mais rápido.
fonte
Esta é uma solução eficiente:
fonte
Os divisores fazem algo espetacular: eles se dividem completamente. Se você deseja verificar o número de divisores para um número
n
, é claramente redundante abranger todo o espectro1...n
,. Não fiz nenhuma pesquisa aprofundada para isso, mas resolvi o problema do Projeto Euler 12 em Números Triangulares . Minha solução para o teste de mais de 500 divisores foi executada por 309504 microssegundos (~ 0,3s). Eu escrevi essa função divisora para a solução.Para todo algoritmo, há um ponto fraco. Eu pensei que isso era fraco contra números primos. Mas, como os números triangulares não são impressos, ele serviu a seu propósito na perfeição. Pelo meu perfil, acho que foi muito bem.
Boas festas.
fonte
numberOfDivisors
e o iterador em 1; isso deve se livrar do erro de divisão por zeroVocê deseja a peneira de Atkin, descrita aqui: http://en.wikipedia.org/wiki/Sieve_of_Atkin
fonte
o método dos números primos é muito claro aqui. P [] é uma lista de números primos menor ou igual a sq = sqrt (n);
fonte
Os livros de teoria dos números chamam a função de contagem de divisores tau. O primeiro fato interessante é que é multiplicativo, ie. τ (ab) = τ (a) τ (b), quando aeb não têm fator comum. (Prova: cada par de divisores de aeb fornece um divisor distinto de ab).
Agora observe que para pa prim, τ (p ** k) = k + 1 (os poderes de p). Assim, você pode calcular facilmente τ (n) a partir de sua fatoração.
No entanto, a fatoração de grandes números pode ser lenta (a segurança da critografia RSA depende do produto de dois primos grandes ser difícil de fatorar). Isso sugere esse algoritmo otimizado
fonte
A seguir, é apresentado um programa em C para encontrar o número de divisores de um determinado número.
A complexidade do algoritmo acima é O (sqrt (n)).
Esse algoritmo funcionará corretamente para o número que é o quadrado perfeito, bem como os números que não são o quadrado perfeito.
Observe que o limite superior do loop é definido como a raiz quadrada do número para que o algoritmo seja mais eficiente.
Observe que armazenar o limite superior em uma variável separada também economiza tempo, você não deve chamar a função sqrt na seção de condição do loop for, isso também economiza seu tempo computacional.
Em vez do loop for acima, você também pode usar o seguinte loop, que é ainda mais eficiente, pois elimina a necessidade de encontrar a raiz quadrada do número.
fonte
Aqui está uma função que eu escrevi. é a pior complexidade de tempo é O (sqrt (n)), por outro lado, é melhor (O (log (n))). Ele fornece todos os principais divisores, juntamente com o número de ocorrências.
fonte
Esta é a maneira mais básica de calcular o número de tesouras:
fonte
@Kendall
Testei seu código e fiz algumas melhorias, agora é ainda mais rápido. Também testei com o código @ هومن جاویدپور, que também é mais rápido que o código dele.
fonte
Não é apenas uma questão de fatorar o número - determinar todos os fatores do número? Você pode decidir se precisa de todas as combinações de um ou mais fatores.
Portanto, um algoritmo possível seria:
Cabe a você combinar os fatores para determinar o restante da resposta.
fonte
Isso é algo que eu criei com base na resposta do Justin. Pode exigir alguma otimização.
fonte
Acho que é isso que você está procurando. Faz exatamente o que você pediu. Se você deseja obter mais informações sobre o produto, por favor, contate nosso departamento de vendas ou solicite um orçamento.
Observe que uma variável CMD não pode suportar valores acima de 999999999
fonte
Eu acho que este será útil e preciso
script.pyton
>>>factors=[ x for x in range (1,n+1) if n%x==0] print len(factors)
fonte
Tente algo como estas:
fonte
Não conheço o método MAIS eficiente, mas faria o seguinte:
Deve funcionar \ o /
Se você precisar, eu posso codificar algo amanhã em C para demonstrar.
fonte