Встроенный тип complex

Комплексные числа - это числа вида a+bi, где:

  • a - действительная часть
  • b - мнимая часть
  • i - мнимая единица, для которой выполняется i^2 = -1

Числа a и b являются действительными. Если a = 0, то комплексное число превращается в чисто мнимое, а если b = 0, то в действительное.

Комплексные числа нужны чтобы получить решение уравнений, которые невозможно решить в действительных числах.

В Python комплексные числа являются встроенным типом данных


complex(real=1, imag=2)
# или
complex("1+2j")

complex() создаёт комплексное число со значением real + imag * 1j или преобразует строку в комплексное число, если первым аргументом передана строка.

В Python используется символ j, но в математике обычно i.

Параметры

  • real - действительная часть (по умолчанию 0)
  • imag - мнимая часть (по умолчанию 0)

Если первый аргумент строка, то он интерпретируется как комплексное число в формате a+bj, a, +bj, -bj. В этом случае второй аргумент передавать не надо - будет ошибка.

При создании из строки формат должен быть строго написан, чтобы Python понял его. Допустимы “a+bj”, “a”, “bj”, “-bj”, “+bj”, но без пробелов около +/- и j. j (или J) - единственно допустимая буква для мнимой единицы. Если cтрока не может быть распознана как комплексное число возникает ValueError.

Если оба аргумента опущены, то возвращается 0j.

Способы создания комплексных чисел в Python


# Удобный и рекомендуемый способ
z1 = 1 + 2j             # (1+2j)

# Через complex()
z2 = complex(1,2)       # (1+2j)
z3 = complex(5)         # (5+0j)
z4 = complex()          # (0+0j)
z5 = complex("1+2j")    # (1+2j)
z6 = complex("-3.5+0j") # (-3.5+0j)
z7 = complex("7j")      # 0+7j

Основные арифметические операции

Все арифметические операции работают как в математике


a = 3 + 4j
b = 1 - 2j

print(a + b)          # (4+2j)
print(a - b)          # (2+6j)
print(a * b)          # (11+2j)
print(a / b)          # (-1+2j)
print(a ** 2)         # (-7+24j)

# Сравнение
# Комплексные числа можно сравнивать только на равенство
print(a == complex(3,4))     # True
print(b == 3+4j)             # False

# Модуль (абсолютное значение)
print(abs(a))         # 5.0
print(abs(0+1j))      # 1.0

Основные методы и атрибуты типа complex()


z = 3 + 4j

print(z.real)          # 3.0     - вещественная часть (всегда float)
print(z.imag)          # 4.0     - мнимая часть (всегда float)
print(z.conjugate())   # (3-4j)  - комплексно-сопряжённое число
print(abs(z))          # 5.0     - модуль числа (|z| = √(a^2 + b^2))

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

Обычный модуль math не работает с комплексными числами. Поэтому чтобы использовать большинство математических операций (для тригонометрии, логарифмов, экспоненты и тд.) нужно использовать библиотеку cmath:


import cmath

print(cmath.sqrt(-1))             # 1j
print(cmath.sqrt(-9))             # 3j

print(cmath.log(-1))              # 3.141592653589793j

print(cmath.sin(1j))              # 1.1752
print(cmath.cos(1j))              # 1.5431

Модуль fractions

Модуль fractions - это стандартная библиотека Python, которая позволяет работать с рациональными числами (обыкновенными дробями) с математической точностью. Библиотека предоставляет класс Fraction для работы с рациональными числами.

В отличие от типа float, который хранит приближённые значения с плавающей точкой и часто даёт ошибки округления(0.1 + 0.2 != 0.3), тип данных Fraction представляет число в виде несократимой дроби вида p/q, где p и q - целые числа, а q != 0.

Fraction является неизменяемым типом данных (immutable), как int, float, str, tuple. Это означает, что после создания объекта Fraction его нельзя изменить - все операции возвращают новый объект.

Преимущества:

  • Абсолютная точность при всех арифметических операциях
  • Автоматическое сокращение дробей

Недостатки:

  • Значительно медленнее float
  • Больший расход памяти

Основные способы создания Fraction


from fractions import Fraction

a = Fraction(3, 4)      # 3/4
b = Fraction(8, 12)     # 2/3  - сразу сокращается
с = Fraction(5)         # 5/1  - если указан только числитель
d = Fraction()          # 0/1 (по умолчанию)

# Из строки
e = Fraction("0.75")    # 3/4  - надёжный способ создания из строки
f = Fraction('3/4')     # 3/4
g = Fraction('2.5')     # 5/2
h = Fraction(' -3/7 ')  # -3/7 - пробелы игнорируются

** Важная рекомендация ** Не создавайте Fraction напрямую из float, если точность важна:


# Плохо - потеря точности
print(Fraction(0.1))           # 3602879701896397/36028797018963968

# Правильно - точное значение
print(Fraction("0.1"))         # 1/10

** Знаменатель всегда > 0, знак хранится в числителе **


a = Fraction(-3, 4)   # -3/4
b = Fraction(3, -4)   # -3/4   - знак переносится в числитель

Арифметические операции

Тип данных Fraction поддерживает все арифметические операции


a = Fraction(1, 3)
b = Fraction(1, 6)

print(a + b)    # 1/2
print(a - b)    # 1/6
print(a * b)    # 1/18
print(a / b)    # 2/1
print(a ** 2)   # 1/9
print(-a)       # -1/3

# С целыми числами
print(Fraction(3, 4) + 1)   # 7/4
print(Fraction(3, 4) * 2)   # 3/2

# С float - результат становится float
print(Fraction(1, 2) + 0.5) # 1.0

Сравнение

Сравнение работает точно так же, как и любые другие числа


Fraction(1, 2) == Fraction(2, 4)  # True
Fraction(1, 3) > Fraction(1, 4)   # True
Fraction(3, 4) < 1                # True
Fraction(4, 2) == 2               # True

# Можно сравнивать с float
Fraction(1, 2) == 0.5             # True

Математические функции

Fraction числа можно передавать как аргументы функций, ожидающих float. Тогда они будут преобразованы во float. К примеру, модуль math, может работать и с Fraction числами.


from fractions import Fraction
from math import *

num1 = Fraction('1.44')
num2 = Fraction('0.523')

print(sqrt(num1))         # 1.2
print(sin(num2))          # 0.4994813555186418
print(log(num1 + num2))   # 0.6744739152943241

Свойства и методы Fraction

Свойства

Для получения отдельно числителя и знаменателя используются свойства numerator и denominator.


from fractions import Fraction
f = Fraction(14, 20)

print(f.numerator)      # 14
print(f.denominator)    # 20

Методы

  • limit_denominator(max_denominator=1000) — находит и возвращает ближайшую дробь к self, у которой знаменатель не превышает max_denominator. Очень полезно для приближения float к рациональным числам или восстановления дробей из float.

f = Fraction('3.1415926535897932').limit_denominator(1000)
print(f)                    # 355/113
  • as_integer_ratio() - Возвращает кортеж (numerator, denominator) — пару целых чисел, равную данной дроби (в несократимом виде, знаменатель > 0).

f = Fraction(3, 4)
print(f.as_integer_ratio())  # (3, 4)
  • is_integer() - Возвращает True, если дробь является целым числом (знаменатель = 1).

Fraction(5, 1).is_integer()  # True
Fraction(5, 2).is_integer()  # False

Модуль decimal

Модуль decimal - это стандартная библиотека Python, предназначенная для точных десятичных вычислений с фиксированной точностью. Библиотека предоставляет класс Decimal для работы с десятичными числами, что особенно важно для финансовых расчетов, бухгалтерии и любых задач, где критически важна точность.

В отличие от типа float, который использует двоичное представление что может приводить к ошибкам округления (0.1 + 0.2 != 0.3), тип Decimal хранит числа в десятичной системе и обеспечивает точность, заданную пользователем.

Decimal является неизменяемым типом данных (immutable), как int, float, str, tuple. Это означает, что после создания объекта Decimal его нельзя изменить - все операции возвращают новый объект.

Преимущества:

  • Точное десятичное представление чисел
  • Контроль над точностью и округлением
  • Поддержка специальных значений (Infinity, -Infinity, NaN)

Недостатки:

  • Значительно медленнее float
  • Требует больше памяти

Основные способы создания Decimal


from decimal import Decimal

# Из целого числа
a = Decimal(10)           # 10
b = Decimal(-5)           # -5

# Из строки (РЕКОМЕНДУЕМЫЙ способ для десятичных дробей)
c = Decimal("10.75")      # 10.75
d = Decimal("-3.14159")   # -3.14159
e = Decimal("0.1")        # 0.1

# Специальные значения
f = Decimal("Infinity")   # Infinity
g = Decimal("-Infinity")  # -Infinity
h = Decimal("NaN")        # NaN (Not a Number)

** Важная рекомендация **

Не создавайте Decimal напрямую из float, если точность важна:


# Плохо - потеря точности
print(Decimal(0.1))       # 0.1000000000000000055511151231257827021181583404541015625

# Правильно - точное значение
print(Decimal("0.1"))     # 0.1

Управление точностью и округлением

Точность и правила округления можно задать через контекст


from decimal import Decimal, getcontext

# Установка точности (количество значащих цифр по умолчанию 28 цифр) 
getcontext().prec = 6           # точность — 6 значащих цифр

print(Decimal(1) / Decimal(3))  # 0.333333

# Смена режима округления
from decimal import ROUND_HALF_UP, ROUND_HALF_EVEN

price = Decimal('19.995')

getcontext().rounding = ROUND_HALF_UP
print(price.quantize(Decimal('0.01')))   # 20.00

getcontext().rounding = ROUND_HALF_EVEN  # банковское округление
print(Decimal('2.5').quantize(Decimal('1')))   # 2
print(Decimal('3.5').quantize(Decimal('1')))   # 4

Ещё отдельные режимы округления:

  • ROUND_CEILING - округление вверх. Всегда округляет в большую сторону Пример: 2.1 = 3, -2.1 = -2

  • ROUND_FLOOR - округление вниз. Всегда округляет в меньшую сторону Пример: 2.9 = 2, -2.9 = -3

  • ROUND_UP - округление от нуля (для положительных — вверх, для отрицательных — вниз) Пример: 2.1 = 3, -2.1 = -3

  • ROUND_DOWN - округление к нулю (усечение) Пример: 2.9 = 2, -2.9 = -2

  • ROUND_HALF_UP - школьное округление (0-4 вниз, 5-9 вверх) Пример: 2.5 = 3, 2.4 = 2

  • ROUND_HALF_DOWN - округление 5 вниз. 0-4 вниз, 6-9 вверх, 5 тоже вниз Пример: 2.5 = 2, 2.6 = 3

  • ROUND_HALF_EVEN - банковское округление 5 округляет к ближайшему четному числу Пример: 2.5 = 2, 3.5 = 4

Уменьшает статистическую погрешность при сериях операций

  • ROUND_05UP - специальное округление. Округляет, если последняя цифра 0 или 5 Пример: 1.04 → 1.0, 1.05 → 1.1 (при точности до 0.1)

Локальный контекст (localcontext)

По умолчанию настройки контекста (точность, округление и флаги ошибок), заданные через getcontext(), являются глобальными и действуют на весь код.

Для временного изменения настроек вычислений используется localcontext(). Он позволяет задать отдельный контекст для ограниченного блока кода, не влияя на остальную программу.

После выхода из блока with все настройки автоматически возвращаются к предыдущему состоянию.


from decimal import Decimal, localcontext, getcontext

# Глобальный контекст
getcontext().prec = 28
print(Decimal(1) / Decimal(3))   # 0.3333333333333333333333333333

# Локальный контекст
with localcontext() as ctx:
    ctx.prec = 6
    print(Decimal(1) / Decimal(3))  # 0.333333

# Глобальный контекст не изменился
print(Decimal(1) / Decimal(3))   # 0.3333333333333333333333333333

Арифметические операции

Тип Decimal поддерживает все арифметические операции с контролем точности:


a = Decimal("10.5")
b = Decimal("3.2")

print(a + b)    # 13.7
print(a - b)    # 7.3
print(a * b)    # 33.6
print(a / b)    # 3.28125
print(a % b)    # 0.9
print(a ** 2)   # 110.25
print(-a)       # -10.5

# Деление с округлением
print(a / b)                            # 3.28125
print((a / b).quantize(Decimal("0.01"))) # 3.28

# Целочисленное деление
print(a // b)   # 3

Сравнение

Сравнение работает точно так же, как и любые другие числа


Decimal("0.1") + Decimal("0.2") == Decimal("0.3")   # True
Decimal("1.5") > Decimal("1.0")                     # True
Decimal("1.5") <= Decimal("1.5")                    # True
Decimal("1.5") != Decimal("1.0")                    # True

# Сравнение со специальными значениями
Decimal("Infinity") > Decimal("1000")               # True
Decimal("NaN") == Decimal("NaN")                    # False (NaN != NaN)

Математические функции

Decimal предоставляет собственные математические методы (sqrt, exp, ln, log10), аналогичные функциям math. Возвращает тип Decimal. Обычные math-функции требуют преобразования в float.


from decimal import Decimal, getcontext
import math

d = Decimal("2.25")

print(d.sqrt())            # 1.5 (квадратный корень)
print(d.exp())             # e^2.25
print(d.ln())              # Натуральный логарифм
print(d.log10())           # Десятичный логарифм

# Тригонометрические функции (нужно установить достаточную точность)
getcontext().prec = 30
angle = Decimal("0.523598775598298873")  # π/6 ≈ 30°
print(angle.sin())         # 0.5 (синус)
print(angle.cos())         # 0.866025403784438646 (косинус)

print(math.sqrt(float(d)))  # 1.5

Свойства и методы Decimal

Свойства для проверки типа числа:


d = Decimal("10.75")
n = Decimal("NaN")
inf = Decimal("Infinity")

print(d.is_finite())                  # True  - проверка на конченое число
print(d.is_infinite())                # False - проверка на бесконченое число
print(d.is_nan())                     # False - проверка на nan
print(d.is_signed())                  # False - проверка на отрицательное число
print(Decimal("-10.75").is_signed())  # True  
print(d.is_zero())                    # False - проверка на ноль

print(n.is_nan())                     # True
print(inf.is_infinite())              # True

Методы для работы с Decimal

  • quantize(exp, rounding=None) - округление до заданной экспоненты:

price = Decimal("15.6789")

# Округление до 2 знаков после запятой
print(price.quantize(Decimal("0.01")))                     # 15.68
print(price.quantize(Decimal("0.01"), rounding=ROUND_DOWN)) # 15.67

# Округление до целого
print(price.quantize(Decimal("1")))        # 16
print(price.quantize(Decimal("1"), rounding=ROUND_DOWN))  # 15
  • to_integral_value(rounding=None) - округление до целого:

d = Decimal("15.78")
print(d.to_integral_value())              # 16
print(d.to_integral_value(ROUND_DOWN))    # 15
  • normalize() - нормализация (убирает лишние нули в конце):

d1 = Decimal("100.00")
d2 = Decimal("1.2E+2")
print(d1.normalize())      # 1E+2 (100 в научной нотации)
print(d2.normalize())      # 1.2E+2

# Для получения привычного вида:
print(d1.normalize().to_eng_string())  # 100
  • as_tuple() - возвращает внутреннее представление числа:

d = Decimal("123.456")
print(d.as_tuple())  
# DecimalTuple(sign=0, digits=(1, 2, 3, 4, 5, 6), exponent=-3)

# Можно восстановить Decimal из кортежа
from decimal import DecimalTuple
t = DecimalTuple(sign=0, digits=(1, 2, 3), exponent=0)
print(Decimal(t))  # 123
  • to_eng_string() - строковое представление в инженерной нотации:

d = Decimal("123456.789")
print(d.to_eng_string())  # 123456.789
  • adjusted() — возвращает порядок числа (экспоненту):

print(Decimal("123.456").adjusted())   # 2 (10^2)
print(Decimal("0.00123").adjusted())   # -3 (10^-3)