Encontrando o conjunto de raízes de equações polinomiais na prática
Muita gente trava na hora de calcular o conjunto de raizes de um polinômio porque começa pelo método errado. A abordagem teórica que ensinam na faculdade funciona bem no papel, mas quando você precisa resolver algo real com coeficientes flutuantes ou grau alto, o caminho tradicional desmorona rápido. Vou explicar primeiro como fazer funcionar antes de entrar na teoria.
O que é e como calcular o conjunto de raizes
O conjunto de raízes é simplesmente a coleção completa de todos os valores que zereiam uma função. No caso de polinômios, são os pontos onde o gráfico cruza (ou toca) o eixo x. Parece elementar, mas a parte complicada aparece quando você lida com raízes complexas, raízes repetidas ou polinômios de grau superior a 4. Para polinômios de grau até 4, a fórmula clássica de Bhaskara (para grau 2) e as fórmulas de Cardano-Ferrari (para graus 3 e 4) ainda são viáveis. Acima disso, você não tem fórmula algébrica geral — o teorema de Abel-Ruffini bloqueia isso. Aí entra numérica de verdade.
Na prática, o método mais confiável para graus altos é o algoritmo de Durand-Kerner (também chamado de método Weierstrass). Ele estima todas as raízes simultaneamente usando iterações em campo complexo. Funciona bem porque não depende de um chute inicial perfeito — diferente de Newton-Raphson, que se você errar o ponto de partida, pode divergir ou convergir para a raiz errada. Eu já perdi meia tarde debugando um solver baseado em Newton para um polinômio de grau 8 com coeficientes mal-escalonados. O problema era que duas raízes estavam tão próximas (diferença da ordem de 10^-7) que o método oscilava entre elas sem convergir de jeito nenhum. A solução foi usar o método Jenkins-Traub, que é basicamente o Durand-Kerner com optimizações de deslocamento de origem. Rodou em segundos. Se estiver trabalhando com Python, a função numpy.roots() usa uma abordagem baseada em autovalores da companion matrix, que é equivalente e bem estável para a maioria dos casos.
Pegadinhas que ninguém conta
A primeira pegadinha é sobre precisão. Raízes de polinômios são intrinsicamente mal-condicionadas em certos cenários. O polinômio de Wilkinson, aquele famoso exemplo com raízes de 1 a 20, mostra exatamente isso: perturbações minúsculas no coeficiente de x^19 geram mudanças caóticas nas raízes calculadas. Se seus coeficientes vêm de medições experimentais com ruído, o conjunto de raizes que você calcular pode não ter relação útil com a realidade. A segunda pegadinha é mais sutil e acontece todo dia em projetos de engenharia: raízes complexas com parte imaginária quase nula. Um solver numérico pode retornar algo como 3.000001 + 0.0000001i, e você precisa decidir se trata de uma raiz real 3 com erro numérico ou de uma raiz complexa legítima. A regra prática que eu uso é: se o módulo da parte imaginária for menor que 1e-10 vezes o módulo da parte real, trato como real e zero a parte imaginária. Isso evita que gráficos e simulações downstream quebrem por causa de números fantasmas.
👉 Clique no botão abaixo para saber mais sobre o assunto!
Também vale lembrar que o conjunto de raízes não é sempre o que parece. Um polinômio como x^4 + 2x^2 + 1 fatorializa para (x^2 + 1)^2, então as raízes são +i e -i, cada uma com multiplicidade 2. Se você só quer o conjunto (sem repetições), são dois elementos. Se quer as raízes com multiplicidade, são quatro. Depende do que seu problema exige. Em controle de sistemas, por exemplo, multiplicidade importa porque raízes repetidas no semi-plano direito indicam instabilidade de ordem superior.
Ferramentas e onde conseguir
Se você quer apenas calcular, numpy resolve na maioria dos casos. Instale com pip e use: numpy.roots([coeficiente_do_grau_n, ..., coeficiente_linear, termo_independente])
Ele retorna um array com todas as raízes, incluindo complexas. Para polinômios com coeficientes reais, as raízes complexas sempre vêm em pares conjugados, o que serve como cheque de sanidade rápido. Para casos que exigem mais controle — como necessidade de raízes com alta precisão ou validação rigorosa — o mpmath é uma opção melhor. Ele permite Arbitrary-Precision e o método findroot funciona bem quando você já tem uma estimativa razoável. A desvantagem é que encontra uma raiz por vez, então para um polinômio de grau 10 você precisa chamar dez vezes com chutes diferentes.
Não recomendo tentar implementar o algoritmo do zero se o objetivo é produção. Erros de subtração cancelada, overflow em coeficientes grandes e instabilidade numérica são fáceis de introduzir e difíceis de detectar. Bibliotecas consolidadas passam por décadas de refinamento nesses pontos.
Quando o método falha completamente
Existe um cenário em que nenhuma abordagem numérica padrão vai te salvar: polinômios com coeficientes extremamente desbalanceados em magnitude. Já vi casos onde coeficientes variavam de 10^-15 a 10^15 no mesmo polinômio. O scaling automático do numpy.roots não consegue compensar isso e o resultado fica completamente corrupto. A solução nesse caso é normalizar o polinômio dividindo todos os coeficientes pela potência 10 mais frequente, ou usar escalonamento de Hilbert antes de passar para o solver. Outro cenário de falha é quando o polinômio é na verdade uma aproximação de Padé ou uma série truncada. O conjunto de raízes calculado pode conter polos fantasmas — raízes que dependem do número de termos da série e não de nada físico. Se estiver modelando um sistema real, sempre valide as raízes contra dados empíricos antes de confiar nelas.