Complex numbers не такі вже й складні.
Їм просто потрібна назва, яка не так лякає.
Вони настільки корисні, особливо в інженерії та науці, що Python включає complex як стандартний числовий тип, поряд із цілими числами (int) і числами з плаваючою комою (float).
Значення complex у Python по суті є парою чисел з плаваючою комою.
Їх називають «дійсною» та «уявною» частинами, з прикрих історичних причин.
І знову ж таки, краще зосередитися на їхній внутрішній простоті, а не на дивних назвах.
Є два поширені способи створити комплексні числа.
complex(real, imag) приймає два параметри типу float:>>> z1 = complex(1.5, 2.0)
>>> z1
(1.5+2j)
Конструктор також уміє розбирати вхідний рядок тексту (англ. string). Це має дивне обмеження: він не спрацьовує, якщо рядок тексту містить пробіли.
>>> 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, або просто <complex part>j, якщо дійсна частина дорівнює нулю:>>> z2 = 2.0 + 1.5j
>>> z2
(2+1.5j)
Результат той самий, що й від використання конструктора complex().
Для уявної частини комплексного числа є два правила:
Її позначають через j (а не i, як іноді буває в підручниках з математики).
j має стояти одразу після числа, щоб Python не сприйняв його як імʼя змінної. За потреби використовуємо 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'>
Більшість інженерів цілком задоволені літерою j.
Більшість науковців і математиків віддають перевагу математичному позначенню i для уявного, але це позначення конфліктує з використанням i на позначення струму в електротехніці.
Тож під час створення Python перемогли електротехніки.
Щоб отримати частини комплексного числа окремо:
>>> z2.real
2.0
>>> z2.imag
1.5
Будь-яка з частин може дорівнювати нулю, і тоді математики кажуть, що число «цілком дійсне» або «цілком уявне». Однак у Python це все одно комплексне число:
>>> complex(0, 1)
1j
>>> type(complex(0, 1))
<class 'complex'>
>>> complex(1, 0)
(1+0j)
Можна почути, що «i (або j) є квадратним коренем із -1».
Поки що все це означає лише те, що уявна частина за визначенням задовольняє рівність
1j * 1j == -1 # => True
Це проста ідея, але вона веде до цікавих наслідків.
Більшість operators, які використовуються з числами з плаваючою комою та цілими числами, також працюють із комплексними числами:
>>> 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)
Пояснення правил множення та ділення комплексних чисел виходить за межі цієї концепції (і навряд чи комусь доведеться часто виконувати ці операції «вручну»).
Будь-який математичний чи електротехнічний вступ до комплексних чисел розкриє це, якщо захочеться заглибитися в тему.
Або ж на Exercism є практична вправа Complex Numbers, де можна реалізувати клас комплексного числа з цими операціями із самих основ.
Цілочисельне ділення для комплексних чисел не можливе, тому оператори // і % та функція divmod() не працюватимуть із типом комплексних чисел.
Для числових типів реалізовано дві функції, які дуже корисні під час роботи з комплексними числами:
<complex number>.conjugate() просто змінює знак уявної частини комплексного числа (з + на - або навпаки).
abs(<complex number>) гарантовано повертає дійсне число без уявної частини.>>> 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
Стандартна бібліотека Python має модуль math, сповнений корисних функцій для роботи з дійсними числами.
У ній також є відповідний модуль cmath для роботи з комплексними числами.
Радимо переглянути цей модуль і поекспериментувати, а основні категорії такі:
Ось приклад із використанням деяких констант:
>>> 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
Отже, простий вираз із трьома найважливішими константами природи e, i (або j) та pi дає результат -1.
Дехто вважає це найкрасивішим результатом у всій математиці.
Він сягає приблизно 1740 року.
Цю частину можна пропустити, якщо нецікаво.
Вона була дивною і новою у XVI столітті.
500 років потому вона лежить в основі більшості інженерних і фізичних наук.
Виявляється, комплексні числа - це найпростіший спосіб описати будь-що, що обертається, або будь-що з хвильовими властивостями. Тож їх широко використовують в електротехніці, обробці звуку, фізиці, компʼютерних іграх і навігації, і це лише кілька прикладів застосування.
Обертання можна побачити будь-де. Можливо, комплексні числа не змушують світ обертатися, але вони чудово пояснюють те, що відбувається внаслідок цього обертання: погляньмо на будь-який супутниковий знімок великої бурі.
Менш очевидно, що звук має хвильову природу, світло має хвильову природу, радіосигнали мають хвильову природу, і навіть економіка нашої країни принаймні частково має хвильову природу.
Значну частину такої обробки хвиль можна виконати за допомогою тригонометричних функцій (sin() і cos()), але це досить швидко стає заплутаним.
З комплексними експонентами працювати набагато простіше.
Це правда, лише якщо жити в печері й добувати їжу полюванням і збиральництвом.
Якщо ми читаємо це з будь-якого екрана, то цілком залежимо від корисних досягнень XX століття, здобутих завдяки використанню комплексних чисел.
Напівпровідникові чипи.
Алгоритм швидкого перетворення Фурʼє (ШПФ).
ШПФ - це застосування комплексних чисел, і воно присутнє в усьому, повʼязаному з передаванням звуку, обробкою аудіо, фотографіями та відео.
MP3 та інші аудіоформати використовують ШПФ для стиснення, завдяки чому більше аудіо вміщується в меншому обсязі памʼяті.
Стиснення JPEG і відео MP4, як і багато інших форматів зображень і відео, також використовують ШПФ для стиснення.
ШПФ також застосовують у цифрових фільтрах, які дають змогу вишкам стільникового звʼязку відокремлювати наш особистий сигнал від сигналів усіх інших.
Тож ми, ймовірно, користуємося технологіями, які покладаються на обчислення комплексних чисел тисячі разів на секунду.