Os Complex numbers não são complicados.
Eles só precisam de um nome menos assustador.
Eles são tão úteis, especialmente na engenharia e na ciência, que o Python inclui complex como um tipo numérico padrão, ao lado dos inteiros (ints) e dos números de ponto flutuante (floats).
Um valor complex no Python é essencialmente um par de números de ponto flutuante.
Eles são chamados de partes "real" e "imaginária", por motivos históricos infelizes.
Mais uma vez, é melhor focar na simplicidade por trás disso e não nos nomes estranhos.
Existem duas formas comuns de criar números complexos.
complex(real, imag) recebe dois parâmetros float:>>> z1 = complex(1.5, 2.0)
>>> z1
(1.5+2j)
O construtor também pode interpretar uma string como entrada. Isso tem a limitação curiosa 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
<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().
Existem duas regras para essa parte imaginária do número complexo:
Ela é indicada com j (não i, como você pode ver em livros de matemática).
O j deve vir imediatamente após um número, para que o Python não o veja como um nome de variável. Se necessário, use 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 fica satisfeita com 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 significar corrente na Engenharia Elétrica.
Então, ao projetar o Python, os engenheiros elétricos venceram.
Para acessar as partes de um número complexo individualmente:
>>> z2.real
2.0
>>> z2.imag
1.5
Qualquer uma das partes pode ser zero, e os matemáticos podem então falar que o número é "totalmente real" ou "totalmente imaginário". Mesmo assim, ele continua sendo um número complexo no Python:
>>> complex(0, 1)
1j
>>> type(complex(0, 1))
<class 'complex'>
>>> complex(1, 0)
(1+0j)
Você pode ter ouvido que "i (ou j) é a raiz quadrada de -1".
Por enquanto, tudo o que isso significa é que a parte imaginária por definição satisfaz a igualdade
1j * 1j == -1 # => True
É uma ideia simples, mas leva a consequências interessantes.
A maioria dos operators usados com números de ponto flutuante 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 de multiplicação e divisão de números complexos está fora do escopo deste conceito (e é pouco provável que você precise fazer essas operações "à mão" com frequência).
Qualquer introdução matemática ou de engenharia elétrica aos números complexos aborda isso, caso você queira se aprofundar no assunto.
Como alternativa, o Exercism tem um exercício de prática Complex Numbers, no qual você pode implementar uma classe de números complexos com essas operações a partir dos primeiros princípios.
A divisão inteira não é possível com números complexos, então os operadores // e % e a função divmod() vão falhar para o tipo de número complexo.
Há duas funções implementadas para tipos numéricos que são muito úteis ao trabalhar 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).
abs(<complex number>) tem a garantia de retornar 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
cmath
A biblioteca padrão do Python tem um módulo math cheio de funcionalidades úteis para trabalhar com números reais.
Ela também tem um módulo equivalente, cmath, para trabalhar com números complexos.
Recomendamos que você leia o módulo e experimente, mas as principais categorias são:
Veja um exemplo usando 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
Então, uma expressão simples com três das constantes mais importantes da natureza, e, i (ou j) e pi, dá o resultado -1.
Algumas pessoas acreditam que este é o resultado mais belo de toda a matemática.
Ele remonta a cerca de 1740.
Esta parte pode ser pulada, a menos que você tenha interesse.
Era estranho e novo no século XVI.
500 anos depois, é central para a maior parte da engenharia e das ciências físicas.
Acontece que os números complexos são a forma mais simples de descrever qualquer coisa que gira ou que tenha uma propriedade ondulatória. Por isso, são amplamente usados em engenharia elétrica, processamento de áudio, física, jogos de computador e navegação, para citar apenas algumas aplicações.
Você consegue ver as coisas girando. Os números complexos podem não fazer o mundo girar, mas são ótimos para explicar o que acontece como resultado do giro do mundo: basta olhar 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 seu país é, pelo menos em parte, ondulatória.
Boa parte desse processamento de ondas pode ser feito com funções trigonométricas (sin() e cos()), mas isso fica confuso bem rápido.
Exponenciais complexas são muito mais fáceis de usar.
Só é verdade se você mora numa caverna e busca seu próprio alimento.
Se você está lendo isto em qualquer tipo de tela, depende totalmente de alguns avanços úteis do século XX obtidos com o uso de números complexos.
Chips semicondutores.
O algoritmo da Transformada Rápida de Fourier (FFT).
A FFT é uma aplicação dos números complexos e está em tudo ligado à transmissão de som, ao processamento de áudio, às fotos e ao vídeo.
MP3 e outros formatos de áudio usam a FFT para compressão, garantindo que mais áudio caiba em um 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 celular separar o sinal do seu telefone do de todo mundo.
Então, você provavelmente usa tecnologia que depende de cálculos com números complexos milhares de vezes por segundo.