Percursos
/
Python
Python
/
Programa
/
Números Complexos
Nú

Números Complexos em Python

{one: "1 exercício", many: "%{count} exercícios", other: "%{count} exercícios"}

Sobre Números Complexos

Os Complex numbers não são complicados. Só precisam de um nome menos assustador.

São tão úteis, sobretudo em engenharia e ciência, que o Python inclui complex como tipo numérico padrão, a par dos inteiros (ints) e dos números de vírgula flutuante (floats).

Noções básicas

Um valor complex em Python é, essencialmente, um par de números de vírgula flutuante. Estas chamam-se as partes "real" e "imaginária", por razões históricas infelizes. Mais uma vez, o melhor é focarmo-nos na simplicidade subjacente e não nos nomes estranhos.

Há duas formas comuns de criar números complexos.

  1. O construtor complex(real, imag) recebe dois parâmetros do tipo float:
>>> z1 = complex(1.5, 2.0)
>>> z1
(1.5+2j)

O construtor também consegue interpretar uma string de entrada. Tem a limitação estranha de falhar se a string contiver espaços.

>>> complex('4+2j')
(4+2j)

>>> complex('4 + 2j')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: complex() arg is a malformed string
  1. O número complexo pode ser escrito como o literal <real part> + <complex part>j, ou apenas <complex part>j se a parte real for zero:
>>> z2 = 2.0 + 1.5j
>>> z2
(2+1.5j)

O resultado final é idêntico ao de usar o construtor complex().

Há duas regras para a parte imaginária do número complexo:

  • É designada por j (e não i, como podes ver nos manuais de matemática).

  • O j tem de vir imediatamente a seguir a um número, para o Python não o interpretar como o nome de uma variável. Se for preciso, usa 1j.

>>> j
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'j' is not defined

>>> 1j
1j

>>> type(1j)
<class 'complex'>

A maioria dos engenheiros dá-se bem com o j. A maioria dos cientistas e matemáticos prefere a notação matemática i para imaginário, mas essa notação entra em conflito com o uso de i para designar corrente em Engenharia Eletrotécnica. Por isso, ao criar o Python, foram os engenheiros eletrotécnicos que ganharam.

Para aceder às partes de um número complexo individualmente:

>>> z2.real
2.0
>>> z2.imag
1.5

Qualquer das partes pode ser zero, e os matemáticos podem então falar de um número "totalmente real" ou "totalmente imaginário". No entanto, em Python continua a ser um número complexo:

>>> complex(0, 1)
1j
>>> type(complex(0, 1))
<class 'complex'>

>>> complex(1, 0)
(1+0j)

Podes ter ouvido dizer que "i (ou j) é a raiz quadrada de -1".

Por agora, tudo o que isto significa é que a parte imaginária satisfaz, por definição, a igualdade

1j * 1j == -1  # => True

É uma ideia simples, mas tem consequências interessantes.

Aritmética

A maioria dos operators usados com floats e inteiros também funciona com números complexos:

>>> z1 = (1.5+2j)
>>> z2 = (2+1.5j)


>>> z1 + z2  # addition
(3.5+3.5j)

>>> z1 - z2  # subtraction
(-0.5+0.5j)

>>> z1 * z2  # multiplication
6.25j

>>> z1 / z2  # division
(0.96+0.28j)

>>> z1 ** 2  # exponentiation
(-1.75+6j)

>>> 2 ** z1  # another exponentiation
(0.5188946835878313+2.7804223253571183j)

>>> 1j ** 2  # j * j == -1
(-1+0j)

Explicar as regras da multiplicação e da divisão de números complexos está fora do âmbito deste conceito (e é pouco provável que tenhas de fazer essas operações "à mão" com muita frequência).

Qualquer introdução matemática ou de engenharia eletrotécnica aos números complexos aborda isto, caso queiras aprofundar o tema.

Em alternativa, o Exercism tem um exercício de prática Complex Numbers onde podes implementar uma classe de números complexos com estas operações, a partir dos primeiros princípios.

A divisão inteira não é possível com números complexos, por isso os operadores // e % e a função divmod() falham com o tipo de número complexo.

Há duas funções implementadas para tipos numéricos que são muito úteis quando trabalhas com números complexos:

  • <complex number>.conjugate() simplesmente inverte o sinal da parte imaginária de um número complexo (de + para -, ou vice-versa).
    • Por causa da forma como funciona a multiplicação de números complexos, isto é mais útil do que imaginas.
  • abs(<complex number>) garante que devolve um número real sem parte imaginária.
>>> z1
(1.5+2j)

>>> z1.conjugate() # flip the z1.imag sign
(1.5-2j)

>>> abs(z1) # sqrt(z1.real ** 2 + z1.imag ** 2)
2.5

O módulo cmath

A biblioteca padrão do Python tem um módulo math cheio de funcionalidades úteis para trabalhar com números reais.

Também tem um módulo equivalente, cmath, para trabalhar com números complexos.

Encorajamos-te a ler o módulo e a experimentar, mas as principais categorias são:

  • Conversão entre coordenadas cartesianas e polares,
  • Funções exponenciais e logarítmicas,
  • Funções trigonométricas,
  • Funções hiperbólicas,
  • Funções de classificação, e
  • Constantes úteis.

Eis um exemplo que usa algumas constantes:

>>> import cmath

>>> euler = cmath.exp(1j * cmath.pi) # Euler's equation

>>> euler.real
-1.0
>>> round(euler.imag, 15) # round to 15 decimal places
0.0

Assim, uma expressão simples com três das constantes mais importantes da natureza, e, i (ou j) e pi, dá o resultado -1. Há quem acredite que este é o resultado mais belo de toda a matemática. Remonta a cerca de 1740.


Secção opcional: perguntas frequentes sobre números complexos

Podes saltar esta parte, a não ser que tenhas interesse.

Isto não é uma estranha novidade da matemática pura?

Era estranho e novo no século XVI.

500 anos mais tarde, é central para a maior parte da engenharia e das ciências físicas.

Porque é que alguém haveria de usar isto?

Acontece que os números complexos são a forma mais simples de descrever tudo o que roda ou tudo o que tem uma propriedade ondulatória. Por isso são amplamente usados em engenharia eletrotécnica, processamento de áudio, física, jogos de computador e navegação, para só referir algumas aplicações.

Consegues ver coisas a rodar. Os números complexos podem não fazer o mundo girar, mas são ótimos para explicar o que acontece quando o mundo gira: olha para qualquer imagem de satélite de uma grande tempestade.

De forma menos óbvia, o som é ondulatório, a luz é ondulatória, os sinais de rádio são ondulatórios, e até a economia do teu país é, pelo menos em parte, ondulatória.

Muito deste processamento de ondas pode ser feito com funções trigonométricas (sin() e cos()), mas isso torna-se confuso muito depressa.

As exponenciais complexas são muito mais fáceis de usar.

Mas eu não preciso de números complexos!

Só é verdade se viveres numa caverna e andares a procurar comida.

Se estás a ler isto em qualquer tipo de ecrã, dependes completamente de alguns avanços úteis do século XX, alcançados através do uso de números complexos.

  1. Chips semicondutores.

    • Não fazem sentido na física clássica e só podem ser explicados (e concebidos) pela mecânica quântica (MQ).
    • Na MQ, tudo tem valor complexo, por definição. (são formas de onda até ao fundo)
  2. O algoritmo da Transformada Rápida de Fourier (FFT).

    • A FFT é uma aplicação dos números complexos, e está em tudo o que esteja ligado à transmissão de som, ao processamento de áudio, às fotografias e ao vídeo.

    • O MP3 e outros formatos de áudio usam a FFT para compressão, garantindo que cabe mais áudio num espaço de armazenamento menor.

    • A compressão JPEG e o vídeo MP4, entre muitos outros formatos de imagem e vídeo, também usam a FFT para compressão.

    • A FFT é também usada nos filtros digitais que permitem às torres de telemóvel separar o teu sinal pessoal do de todas as outras pessoas.

Por isso, provavelmente usas tecnologia que depende de cálculos com números complexos milhares de vezes por segundo.

Editar via GitHub A ligação abre numa nova janela ou separador