Los Complex numbers no son complicados.
Solo necesitan un nombre menos alarmante.
Son tan útiles, sobre todo en la ingeniería y la ciencia, que Python incluye complex como un tipo numérico estándar, junto con los enteros (ints) y los números de punto flotante (floats).
Un valor complex en Python es, en esencia, un par de números de punto flotante.
Se llaman la parte «real» y la parte «imaginaria», por desafortunadas razones históricas.
De nuevo, lo mejor es centrarse en la sencillez que hay debajo y no en los nombres extraños.
Hay dos formas comunes de crear números complejos.
complex(real, imag) recibe dos parámetros de tipo float:>>> z1 = complex(1.5, 2.0)
>>> z1
(1.5+2j)
El constructor también puede analizar una entrada de tipo string. Tiene la curiosa limitación de que falla si el string contiene espacios.
>>> 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, o solo <complex part>j si la parte real es cero:>>> z2 = 2.0 + 1.5j
>>> z2
(2+1.5j)
El resultado final es idéntico al de usar el constructor complex().
Hay dos reglas para esa parte imaginaria del número complejo:
Se designa con j (no con i, como podrías ver en los libros de matemáticas).
La j debe ir inmediatamente después de un número, para que Python no la vea como un nombre de variable. Si es necesario, 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'>
La mayoría de los ingenieros están contentos con j.
La mayoría de los científicos y matemáticos prefieren la notación matemática i para imaginario, pero esa notación entra en conflicto con el uso de i para referirse a la corriente en la ingeniería eléctrica.
Así que, al diseñar Python, ganaron los ingenieros eléctricos.
Para acceder a las partes de un número complejo individualmente:
>>> z2.real
2.0
>>> z2.imag
1.5
Cualquiera de las dos partes puede ser cero, y entonces los matemáticos pueden hablar de que el número es «totalmente real» o «totalmente imaginario». Sin embargo, en Python sigue siendo un número complejo:
>>> complex(0, 1)
1j
>>> type(complex(0, 1))
<class 'complex'>
>>> complex(1, 0)
(1+0j)
Puede que hayas oído que «i (o j) es la raíz cuadrada de -1».
Por ahora, todo esto significa que la parte imaginaria, por definición, cumple la igualdad
1j * 1j == -1 # => True
Es una idea sencilla, pero conduce a consecuencias interesantes.
La mayoría de los operators que se usan con números de punto flotante y enteros también funcionan con números complejos:
>>> 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 las reglas de la multiplicación y la división de números complejos queda fuera del alcance de este concepto (y es poco probable que tengas que hacer esas operaciones «a mano» muy a menudo).
Cualquier introducción matemática o de ingeniería eléctrica a los números complejos lo tratará, si quieres profundizar en el tema.
Como alternativa, Exercism tiene un ejercicio de práctica Complex Numbers donde puedes implementar una clase de números complejos con estas operaciones desde los fundamentos.
La división entera no es posible con números complejos, así que los operadores // y % y la función divmod() fallarán con el tipo de número complejo.
Hay dos funciones implementadas para los tipos numéricos que son muy útiles cuando se trabaja con números complejos:
<complex number>.conjugate() simplemente cambia el signo de la parte imaginaria de un número complejo (de + a - o viceversa).
abs(<complex number>) garantiza devolver un número real sin parte imaginaria.>>> 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
La biblioteca estándar de Python tiene un módulo math lleno de funcionalidades útiles para trabajar con números reales.
También tiene un módulo cmath equivalente para trabajar con números complejos.
Te animamos a leer el módulo y experimentar, pero las categorías principales son:
Aquí tienes un ejemplo que usa algunas 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
Así que una expresión sencilla con tres de las constantes más importantes de la naturaleza, e, i (o j) y pi, da como resultado -1.
Algunas personas creen que es el resultado más bello de todas las matemáticas.
Se remonta a alrededor de 1740.
Puedes saltarte esta parte, a menos que te interese.
Era extraña y nueva en el siglo XVI.
500 años después, es fundamental en la mayor parte de la ingeniería y de las ciencias físicas.
Resulta que los números complejos son la forma más sencilla de describir cualquier cosa que rote o cualquier cosa con una propiedad similar a una onda. Por eso se usan ampliamente en la ingeniería eléctrica, el procesamiento de audio, la física, los videojuegos y la navegación, por nombrar solo algunas aplicaciones.
Puedes ver cómo giran las cosas. Puede que los números complejos no hagan girar el mundo, pero son excelentes para explicar qué pasa como resultado de que el mundo gire: mira cualquier imagen satelital de una gran tormenta.
Menos evidente: el sonido es similar a una onda, la luz es similar a una onda, las señales de radio son similares a una onda, e incluso la economía de tu país es, al menos en parte, similar a una onda.
Gran parte de este procesamiento de ondas se puede hacer con funciones trigonométricas (sin() y cos()), pero eso se vuelve complicado muy rápido.
Las exponenciales complejas son mucho más fáciles de manejar.
Solo es cierto si vives en una cueva y buscas tu comida.
Si estás leyendo esto en cualquier tipo de pantalla, dependes por completo de algunos avances útiles del siglo XX que se lograron gracias al uso de los números complejos.
Chips semiconductores.
El algoritmo de la transformada rápida de Fourier (FFT).
La FFT es una aplicación de los números complejos, y está en todo lo relacionado con la transmisión de sonido, el procesamiento de audio, las fotos y el video.
El MP3 y otros formatos de audio usan la FFT para comprimir, lo que permite que quepa más audio en un espacio de almacenamiento más pequeño.
La compresión JPEG y el video MP4, entre muchos otros formatos de imagen y video, también usan la FFT para comprimir.
La FFT también se usa en los filtros digitales que permiten a las torres de telefonía celular separar la señal de tu celular de la de todos los demás.
Así que probablemente usas tecnología que depende de cálculos con números complejos miles de veces por segundo.