Estou trabalhando em um pequeno programa python para mim e preciso de um algoritmo para multiplicação rápida de uma enorme matriz com números (mais de 660.000 números, cada um com 9 dígitos). O número do resultado tem mais de 4 milhões de dígitos. Atualmente estou usando math.prod, que calcula em aproximadamente 10 minutos, mas é muito lento, especialmente se eu quiser aumentar a quantidade de números.
Verifiquei alguns algoritmos para multiplicações mais rápidas, por exemplo o algoritmo de Schönhage-Strassen e a multiplicação de Toom-Cook, mas não entendi como eles funcionam ou como fazê-los. Tentei algumas versões que encontrei na internet, mas não funcionam muito bem e são ainda mais lentas. Gostaria de saber se alguém sabe como multiplicar essas quantidades de números mais rapidamente ou poderia explicar como usar um pouco de matemática para fazer isso?
math.prod
acumulará um produto, um número de cada vez. Você pode fazer melhor dividindo recursivamente a lista, pegando o produto de cada metade, por exemplo, o que reduz o tamanho dos produtos intermediários.Isso é executado em alguns segundos para mim:
Tenho usado um método complicado, sempre multiplicando os dois números mais antigos ainda não multiplicados até que reste apenas um:
Quase tão rápido quanto o de @Ry-. A velocidade vem de Karatsuba entrando em ação ao multiplicar dois números grandes em vez de um grande e um minúsculo.
E usar
decimal
parece cerca de cinco vezes mais rápido devido aos algoritmos de multiplicação ainda mais rápidos (e tem a vantagem de ser muito mais rápido para imprimir em decimal, se você quiser):Existem duas chaves para tornar isso rápido. Primeiro, usando a implementação múltipla mais rápida que você pode obter. Para multiplicandos "suficientemente grandes", o Karatsuba mult do Python é
O(n^1.585)
. Odecimal
mult NTT muito mais sofisticado do módulo é mais parecido comO(n log n)
. Mas o mais rápido de tudo é instalar ogmpy2
pacote de extensão, que envolve a biblioteca GMP do GNU, cujo objetivo principal é a velocidade máxima. Isso tem essencialmente a mesma assintótica quedecimal
mult, mas com um fator constante menor.Em segundo lugar, os algoritmos múltiplos avançados funcionam melhor ao multiplicar dois inteiros grandes com aproximadamente o mesmo tamanho (número de bits). Você pode deixar isso para a sorte ou, como abaixo, pode forçá-lo usando uma fila de prioridade e, a cada passo, multiplicando os “dois menores” produtos parciais restantes.
Esse é o código que eu usaria. Observe que o custo da recursão (que não é usado) é trivial comparado ao custo da aritmética enorme. As operações de heap são mais caras que a recursão, mas ainda relativamente baratas, e podem muito mais do que reembolsar seu custo se a entrada estiver em uma ordem tal que os métodos "por sorte" não tenham sorte o suficiente.