cmath - математические функции для работы с комплексными числами

Модуль cmath предоставляет доступ к функциям, которые могут выполнять математические действия над комплексными числами. Помимо комплексных чисел, аргументами данных функций могут быть как целые так и вещественные (с плавающей точкой) числа, а так же любые объекты языка Python с методами __complex__() или __float__(), необходимые для преобразования комплексных чисел в вещественные и наоборот.

Некоторые функции комплексного переменного являются многозначными, поэтому для них необходимо определить ту область в которой их значение будет однозначным, а сама функция непрерывна. Такие области называются листами, а их края разрезами.

Наличие модуля cmath наряду с модулем math необходимо лишь потому что зачастую, комплексные числа вовсе не нужны. Например, кого-то сбивает с толку выражение:

>>> (-1)**0.5
(6.123233995736766e-17+1j)

Потому что некоторая часть программистов, вообще никак не связана с математикой и для них такое поведение не то что бы является странным - оно вообще является нежелательным. Поэтому они и пользуются библиотекой math, которая в этом случае просто выдаст ошибку:

>>> import math
>>> 
>>> math.sqrt(-1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: math domain error

Модуль cmath в свою очередь, всегда возвращает комплексные числа, даже если для вывода достаточно целого или вещественного типа данных, просто множитель перед мнимой единицей будет равен нулю:

>>> cmath.sin(0)
0j
>>> cmath.sin(-0.0)
(-0+0j)

Степенные и логарифмические функции

cmath.exp(x)
вычисляет экспоненту комплексного числа.

Для комплексного числа \(x = a+ib\) экспонента определяется как \(e^{x}=e^{a}e^{ib}\), где \(e^{a}\) – это экспонента вещественного числа, а \(e^{ib}\) – это \(\cos b + i\sin b\).

>>> import cmath
>>> 
>>> cmath.exp(0+0j)
(1+0j)
>>> 
>>> 
>>> x = 0 + (cmath.pi/2)*1j
>>> cmath.exp(x)
(6.123233995736766e-17+1j)
>>> 
>>> cmath.e**x
(6.123233995736766e-17+1j)
cmath.log(x[, base])
вычисляет логарифм комплексного числа с указанным основанием, если основание не указано, то возвращается значение натурального логарифма.

Для данной функции определен единственный, непрерывный сверху разрез главной ветви вдоль отрицательной действительной оси от \(0\) до \(-\infty\).

Как правило, на практике используется именно натуральный логарифм (обозначается \(\mathrm {Ln} \,z\) ), который так же как и логарифм для других оснований, определяется как функция обратная к показательной. Например, для комплексного числа \(x = a+ib\) натуральный логарифм определяется как некоторое значение \(\omega\), которое является решением уравнения \(e^{\omega}=x\).

>>> import cmath
>>> 
>>> cmath.log(1 + 0j)
0j
>>> 
>>> cmath.log(0 + 1j)
1.5707963267948966j
>>> 
>>> 
>>> cmath.log(1 + 1j, 2)
(0.5+1.1330900354567985j)
cmath.log10(x)
вычисляет десятичный логарифм комплексного числа.

Имеет тот же разрез главной ветви, что и log().

>>> import cmath
>>> 
>>> x = 10**(2 + 0.5j)
>>> x
(40.73073101539468+91.32911666577952j)
>>> 
>>> cmath.log10(x)
(2+0.5j)
cmath.sqrt(x)
вычисляет квадратный корень комплексного числа.

Имеет тот же разрез главной ветви, что и log().

Для одного комплексного числа всегда существуют два значения его квадратного корня, например:

>>> (2 - 1j)**2, (-2 + 1j)**2
((3-4j), (3-4j))

Но с учетом разреза главной ветви, будет возвращено только одно из них, имеющее положительную действительную часть:

>>> import cmath
>>> 
>>> cmath.sqrt(3 - 4j)
(2-1j)

Полярные координаты

Комплексное число в языке Python представляется в виде координаты точки на плоскости с прямоугольной системой координат и хранится в виде:

z == z.real + z.imag*1j

где z.real – это действительная часть (соответствует оси \(x\)), z.imag – мнимая часть (соответствует оси \(y\)), 1j – мнимая единица в языке Python.

Однако, помимо представления комплексных чисел в прямоугольной системе координат, существует еще один альтернативный способ — представление в полярной системе координат. В полярных координатах комплексное число определяется его модулем – длиной радиус-вектора \(\bar{r}\), соединяющим начало координат и точку \(z\), и, его аргументом – углом \( \varphi \) между радиус вектором и положительной частью оси \(x\), откладываемым против часовой стрелки, который еще называют фазовым углом или фазой.

Представленные ниже функции позволяют переводить комплексные числа из одной системы координат в другую.

cmath.phase(x)
Возвращает фазу (так же известную как фазовый угол или аргумент) комплексного числа.

Данная функция эквивалентна команде math.atan2 (x.imag, x.real), т.е. это арктангенс, который возвращает значения из интервала \([-\pi;\pi]\) (в радианах) причем, возвращаемое значение фазы будет находиться в правильном квадранте, так как знаки x.imag и x.real известны.

Для данной функции определен единственный, непрерывный сверху разрез главной ветви вдоль отрицательной действительной оси от \(0\) до \(-\infty\). В системах с поддержкой нулей со знаком (в которых \(-0\) и \(0\) это разные числа) т.е. в большинстве систем, знак результата совпадает с x.imag, даже если x.imag = 0, например:

>>> import cmath
>>> 
>>> cmath.phase(complex(-5.0, 0.0))
3.141592653589793
>>> 
>>> cmath.phase(complex(-5.0, -0.0))
-3.141592653589793

Возвращаемые значения являются радианной мерой угла, что бы конвертировать их в градусные значения можно воспользоваться функцией math.degrees(x):

>>> import cmath, math
>>> 
>>> phi = cmath.phase(3 + 3j)
>>> phi
0.7853981633974483
>>> 
>>> math.degrees(phi)
45.0

В модуле cmath нет функции для вычисления модуля комплексного числа, если вам необходимо вычислить его воспользуйтей функцией abs() модуля math.

cmath.polar(x)
Возвращает полярные координаты комплексного числа.

Возвращает кортеж вида (r, phi), где \(r\) – это модуль комплексного числа, a phi – это его фазовый угол \(\varphi\). Данная функция эквивалентна команде (math.abs(x), cmath.phase(x)).

>>> import cmath
>>> 
>>> x = cmath.polar(3 - 3j)
>>> x
(4.242640687119285, -0.7853981633974483)
>>> 
>>> r, phi = x
>>> 
>>> cmath.rect(r, phi)
(3-2.9999999999999996j)
cmath.rect(r, phi)
вычисляет действительную и мнимую части комплексного числа по его полярным координатам и возвращает полученное число.

Данная функция эквивалентна команде r*(math.cos(phi) + math.sin(phi)*1j).

>>> import cmath
>>> 
>>> cmath.rect(7, 0.7)
(5.35389531099142+4.509523810663837j)
>>> 
>>> cmath.polar(cmath.rect(7, 0.7))
(7.000000000000001, 0.6999999999999998)

Тригонометрические функции

cmath.sin(x)
возвращает синус комплексного числа.
>>> import cmath
>>> 
>>> cmath.sin(0)
0j
>>> cmath.sin(1)
(0.8414709848078965+0j)
>>> 
>>> cmath.sin(1 + 1j)
(1.2984575814159773+0.6349639147847361j)
>>> 
>>> cmath.asin(cmath.sin(1 + 1j))
(1+1j)
cmath.cos(x)
возвращает косинус комплексного числа.
>>> import cmath
>>> 
>>> cmath.cos(0)
(1-0j)
>>> 
>>> cmath.cos(1)
(0.5403023058681398-0j)
>>> 
>>> cmath.cos(1 + 1j)
(0.8337300251311491-0.9888977057628651j)
>>> 
>>> cmath.acos(cmath.cos(1 + 1j))
(0.9999999999999999+1j)
cmath.tan(x)
возвращает тангенс комплексного числа.
>>> import cmath
>>> 
>>> cmath.tan(0)
0j
>>> 
>>> cmath.tan(1)
(1.5574077246549023+0j)
>>> 
>>> cmath.tan(1 + 1j)
(0.27175258531951174+1.0839233273386946j)
>>> 
>>> cmath.atan(cmath.tan(1 + 1j))
(1+1j)
cmath.asin(x)
возвращает арксинус комплексного числа.

Для данной функции заданы два разреза главной ветви, оба вдоль действительной оси: первый \((-\infty , -1]\) непрерывный сверху, второй \([1 , +\infty)\) непрерывный снизу.

>>> import cmath
>>> 
>>> x = cmath.sin(1 + 1j)
>>> x
(1.2984575814159773+0.6349639147847361j)
>>> 
>>> cmath.asin(x)
(1+1j)
cmath.acos(x)
возвращает арккосинус комплексного числа.

Для данной функциидва заданы два разреза главной ветви, оба вдоль действительной оси: первый \((-\infty , -1]\) непрерывный сверху, второй \([1 , +\infty)\) непрерывный снизу.

>>> import cmath
>>> 
>>> x = cmath.cos(1 + 1j)
>>> x
(0.8337300251311491-0.9888977057628651j)
>>> 
>>> cmath.acos(x)
(0.9999999999999999+1j)
cmath.atan(x)
возвращает арктангенс комплексного числа.

Для данной функциидва заданы два разреза главной ветви, оба вдоль мнимой оси: первый \((-\infty i , -1i]\) непрерывный слева, второй \([1i , +\infty i)\) непрерывный справа.

>>> import cmath
>>> 
>>> x = cmath.tan(1 + 1j)
>>> x
(0.27175258531951174+1.0839233273386946j)
>>> 
>>> cmath.atan(x)
(1+1j)

Гиперболические функции

cmath.sinh(x)
возвращает гиперболический синус комплексного числа.
>>> import cmath
>>> 
>>> cmath.sinh(3)
(10.017874927409903+0j)
>>> 
>>> cmath.sinh(1 + 1j)
(0.6349639147847361+1.2984575814159773j)
cmath.cosh(x)
возвращает гиперболический косинус комплексного числа.
>>> import cmath
>>> 
>>> cmath.cosh(0)
(1+0j)
>>> 
>>> cmath.cosh(3)
(10.067661995777765+0j)
>>> 
>>> cmath.cosh(1 + 1j)
(0.8337300251311491+0.9888977057628651j)
cmath.tanh(x)
возвращает гиперболический тангенс комплексного числа.
>>> import cmath
>>> 
>>> cmath.tanh(0)
0j
>>> 
>>> cmath.tanh(3)
(0.9950547536867305+0j)
>>> 
>>> cmath.tanh(1 + 1j)
(1.0839233273386946+0.27175258531951174j)
cmath.asinh(x)
возвращает гиперболический арксинус комплексного числа.

Для данной функциидва заданы два разреза главной ветви, оба вдоль мнимой оси: первый \((-\infty i , -1i]\) непрерывный слева, второй \([1i , +\infty i)\) непрерывный справа.

>>> import cmath
>>> 
>>> x = cmath.sinh(1 + 1j)
>>> x
(0.6349639147847361+1.2984575814159773j)
>>> 
>>> cmath.asinh(x)
(1+1j)
cmath.acosh(x)
возвращает гиперболический арккосинус комплексного числа.

Для данной функции задан один разрез главной ветви вдоль вещественной оси \((- \infty, 1]\) непрерывный сверху.

>>> import cmath
>>> 
>>> x = cmath.cosh(1 + 1j)
>>> x
(0.8337300251311491+0.9888977057628651j)
>>> 
>>> cmath.acosh(x)
(1+0.9999999999999999j)
cmath.atanh(x)
возвращает гиперболический арктангенс комплексного числа.

Для данной функциидва заданы два разреза главной ветви, оба вдоль действительной оси: первый \((-\infty , -1]\) непрерывный сверху, второй \([1 , +\infty)\) непрерывный снизу.

>>> import cmath
>>> 
>>> x = cmath.tanh(1 + 1j)
>>> x
(1.0839233273386946+0.27175258531951174j)
>>> 
>>> cmath.atanh(x)
(1+1j)

Классифицирующие функции

cmath.isfinite(x)
возвращает True если вещественная и (или) мнимая части не равны inf, -inf или nan.
>>> import cmath, math
>>> 
>>> x = complex(math.inf, 3)
>>> y = complex(3, -math.inf)
>>> z = complex(3, math.nan)
>>> 
>>> x, y, z
((inf+3j), (3-infj), (3+nanj))
>>> 
>>> cmath.isfinite(x)
False
>>> cmath.isfinite(y)
False
>>> cmath.isfinite(z)
False
>>> 
>>> 
>>> cmath.isfinite(1000 + 0.001j)
True

Доступно в Python c версии 3.2.

cmath.isinf(x)
возвращает True только если вещественная и (или) мнимая части равны inf, -inf.
>>> import cmath, math
>>> 
>>> x = complex(math.inf, 3)
>>> y = complex(3, -math.inf)
>>> z = complex(3, math.nan)
>>> 
>>> x, y, z
((inf+3j), (3-infj), (3+nanj))
>>> 
>>> cmath.isinf(x)
True
>>> cmath.isinf(y)
True
>>> cmath.isinf(z)
False
cmath.isnan(x)
возвращает True только если вещественная и (или) мнимая части равны nan.
>>> import cmath, math
>>> 
>>> x = complex(math.nan, math.nan)
>>> y = complex(3, math.nan)
>>> z = complex(300, 300)
>>> 
>>> x, y, z
((nan+nanj), (3+nanj), (300+300j))
>>> 
>>> cmath.isnan(x)
True
>>> cmath.isnan(y)
True
>>> cmath.isnan(z)
False
cmath.isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0)
возвращает True если в пределах указанной точности, числа a и b близки настолько, что их можно считать равными.

Допустим у нас есть два числа и мы знаем, что по сути это одно и то же число, а все мизерные различия связаны с ошибками округления и двоичной арифметикой. Мы то понимаем что это как бы одно и то же число, а вот компьютер считает иначе:

>>> import cmath
>>> 
>>> x = 1 + 1j
>>> 
>>> y = cmath.acos(cmath.cos(x))
>>> y
(0.9999999999999999+1j)
>>> 
>>> 
>>> x == y
False

Для таких ситуаций, в которых мы готовы считаться с некоторой погрешностью и подходит функция isclose():

>>> cmath.isclose(x, y)
True

Считать числа близкими или нет, определяют два параметра rel_tol и abs_tol().

rel_tol (relative tolerances) – это относительный допуск, определяемый как максимально допустимая разница между числами a и b относительно большего из них по модулю. По умолчанию, rel_tol = 1e-09, это гарантирует, что числа a и b будут одинаковы, в пределах 9 десятичных цифр. Что бы числа считались равными, если они, допустим, отличаются меньше чем на 0.1%, то достаточно установить rel_tol = 0.001, но в любом случае данный параметр, должен быть больше нуля:

>>> y
(0.9999999999999999+1j)
>>> 
>>> z = 0.999 + 1j
>>> 
>>> cmath.isclose(y, z)
False
>>> 
>>> cmath.isclose(y, z, rel_tol = 0.001)
True

Параметр abs_tol (absolute tolerances) – это минимальный абсолютный допуск, который определяет как сравнивать значения близкие к нулю. Данный параметр должен быть не меньше нуля:

>>> x = 2**(-1000) + 3**(-100)*1j
>>> x
(9.332636185032189e-302+1.9403252174826328e-48j)
>>> 
>>> y = 0.000000000001 + 0.000000000001j
>>> y
(1e-12+1e-12j)
>>> 
>>> cmath.isclose(x, y)
False
>>> cmath.isclose(x, y, abs_tol = 10.0e-13)
False
>>> cmath.isclose(x, y, abs_tol = 10.0e-12)
True

Данная функция эквивалентна команде abs(a - b) <= max(rel_tol*max(abs(a), abs(b)), abs_tol). Значения inf, -inf считаются близкими только сами к себе, а NaN не является близким ни к одному значению, включая само NaN.


Математические константы

cmath.pi
математическая константа \( \pi\) в виде числа типа float.
>>> import cmath
>>> 
>>> cmath.pi
3.141592653589793
cmath.e
математическая константа \( e\) в виде числа типа float.
>>> import cmath
>>> 
>>> cmath.e
2.718281828459045