Язык Python предоставляет три типа значений с плавающей точкой:
встроенные типы float
и complex
и тип decimal.Decimal
в
стандартной библиотеке. Все три типа данных относятся к категории
неизменяемых. Тип float
представляет числа с плавающей точкой
двойной точности, диапазон значений которых зависит от компилятора
языка C (или C\# или Java), применявшегося для компиляции интерпретатора
Python. Числа этого типа имеют ограниченную точность и не могут
надежно сравниваться на равенство значений. Числа типа float
записываются с десятичной точкой или в экспоненциальной форме записи,
например, 0.0
, 4.
, 5.7
, -2.5
, -2e9
, 8.9e-4
.
В машинном представлении числа с плавающей точкой хранятся как
двоичные числа. Это означает, что одни дробные значения могут быть
представлены точно (такие как 0.5
), а другие – только приблизительно
(такие как 0.1
и 0.2
). Кроме того, для представления используется
фиксированное число битов, поэтому существует ограничение на
количество цифр в представлении таких чисел. Ниже приводится
поясняющий пример:
>>> 0.0, 5.4, -2.5, 8.9e-4
Проблема потери точности – это не проблема, свойственная только языку Python; все языки программирования обнаруживают проблему с точным представлением чисел с плавающей точкой.
Если действительно необходимо обеспечить высокую точность,
можно использовать числа типа decimal.Decimal
. Эти числа
обеспечивают уровень точности, который вы укажете (по умолчанию 28
знаков после запятой), и могут точно представлять периодические числа,
такие как \( 0.1 \) , но скорость работы с такими числами существенно
ниже, чем с обычными числами типа float
. Вследствие высокой точности
числа типа decimal.Decimal
прекрасно подходят для производства
финансовых вычислений.
Смешанная арифметика поддерживается таким образом, что результатом
выражения с участием чисел типов int
и float
является число типа
float
, а с участием типов float
и complex
результатом является
число типа complex
. Поскольку числа типа decimal.Decimal
имеют
фиксированную точность, они могут участвовать в выражениях только с
другими числами decimal.Decimal
и с числами типа int
; результатом
таких выражений является число decimal.Decimal
. В случае попытки
выполнить операцию над несовместимыми типами возбуждается исключение
TypeError
.
Все числовые операторы и функции, представленные в
табл. 1, могут применяться к числам типа float,
включая комбинированные операторы присваивания. Тип данных float может
вызываться как функция – без аргументов возвращается число 0.0
, с
аргументом типа float возвращается копия аргумента, а с аргументом
любого другого типа предпринимается попытка выполнить преобразование
указанного объекта в тип float. При преобразовании строки
аргумент может содержать либо простую форму записи числа с десятичной
точкой, либо экспоненциальное представление числа. При выполнении
операций с числами типа float может возникнуть ситуация,
когда в результате получается значение NaN
(not a number – не
число) или «бесконечность». К сожалению, поведение интерпретатора в
таких ситуациях может отличаться в разных реализациях и зависит от
математической библиотеки системы.
Ниже приводится пример простой функции, выполняющей сравнение чисел типа float на равенство в пределах машинной точности:
def equal_float(a, b):
return abs(a - b) <= sys.float_info.epsilon
Чтобы воспользоваться этой функцией, необходимо импортировать
модуль sys
. Объект sys.float_info
имеет множество атрибутов. Так,
sys.float_info.epsilon
хранит минимально возможную разницу между
двумя числами с плавающей точкой. На одной из 32-разрядных машин
автора книги это число чуть больше \( 0.000 000 000 000 000 2 \).
Тип float
в языке Python обеспечивает надежную точность до 17
значащих цифр.
В дополнение к встроенным функциональным возможностям работы
с числами типа float
модуль math
предоставляет множество функций,
которые приводятся в табл. datatype:tbl:4. Ниже приводятся
несколько фрагментов программного кода, демонстрирующих, как можно
использовать функциональные возможности модуля:
>>> import math
>>> math.pi * (5 ** 2)
78.539816339744831
>>> math.hypot(5, 12)
13.0
>>> math.modf(13.732)
(0.73199999999999932, 13.0)
Модуль math
в значительной степени опирается на математическую
библиотеку, с которой был собран интерпретатор Python. Это означает,
что при некоторых условиях и в граничных случаях функции модуля могут
иметь различное поведение на различных платформах.
Таблица 4. Функции и константы модуля math
Синтаксис | Описание |
math.acos(x) | Возвращает арккосинус x в радианах |
math.acosh(x) | Возвращает гиперболический арккосинус x в радианах |
math.asin(x) | Возвращает арксинус x в радианах |
math.asinh(x) | Возвращает гиперболический арксинус x в радианах |
math.atan(x) | Возвращает арктангенс x в радианах |
math.atan2(y x) | Возвращает арктангенс y/x в радианах |
math.atanh(x) | Возвращает гиперболический арктангенс x в радианах |
math.ceil(x) | Возвращает $ | x | $, то есть наименьшее целое число типа int , большее и равное x , например, math.ceil(5.4) == 6 |
math.copysign(x y) | Возвращает x со знаком числа y |
math.cos(x) | Возвращает косинус x в радианах |
math.cosh(x) | Возвращает гиперболический косинус x в радианах |
math.degrees(r) | Преобразует число r типа float из радианов в градусы |
math.e | Константа \( e \), примерно равная значению \( 2.7182818284590451 \) |
math.exp(x) | Возвращает \( e^x \), то есть math.e ** x |
math.fabs(x) | Возвращает $ | x | $, то есть абсолютное значение x в виде числа типа float |
math.factorial(x) | Возвращает \( x! \) |
math.floor(x) | Возвращает $ | x | $, то есть наименьшее целое число типа int , меньшее и равное x , например, math.floor(5.4) == 5 |
math.fmod(x y) | Выполняет деление по модулю (возвращает остаток) числа x на число y ; дает более точный результат, чем оператор % , применительно к числам типа float |
math.frexp(x) | Возвращает кортеж из двух элементов с мантиссой (в виде числа типа float ) и экспонентой (в виде числа типа int ) |
math.fsum(i) | Возвращает сумму значений в итерируемом объекте i в виде числа типа float |
math.hypot(x y) | Возвращает \( \sqrt{x^2 + y^2} \) |
math.isinf(x) | Возвращает True , если значение x типа float является бесконечностью (\( \pm \infty \)) |
math.isnan(x) | Возвращает True , если значение x типа float не является числом |
math.ldexp(m e) | Возвращает \( m\times 2^e \) – операция обратная math.frexp() |
math.log(x b) | Возвращает \( \log_b x \), аргумент b является необязательным и по умолчанию имеет значение math.e |
math.log10(x) | Возвращает \( log_{10} x \) |
math.log1p(x) | Возвращает \( log_e (1+x) \); дает точные значения даже когда значение x близко к 0 |
math.modf(x) | Возвращает дробную и целую часть числа x в виде двух значений типа float |
math.pi | Константа \( \pi \), примерно равная \( 3.1415926535897931 \) |
math.pow(x y) | Возвращает \( x^y \) в виде числа типа float |
math.radians(d) | Преобразует число d типа float из градусов в радианы |
math.sin(x) | Возвращает синус x в радианах |
math.sinh(x) | Возвращает гиперболический синус x в радианах |
math.sqrt(x) | Возвращает \( \sqrt{x} \) |
math.tan(x) | Возвращает тангенс x в радианах |
math.tanh(x) | Возвращает гиперболический тангенс x в радианах |
math.trunc(x) | Возвращает целую часть числа x в виде значения типа int ; то же самое что и int(x) |
Тип данных complex
относится к категории неизменяемых и хранит пару
значений типа float
, одно из которых представляет действительную
часть комплексного числа, а другое – мнимую. Литералы комплексных
чисел записываются как действительная и мнимая части, объединенные
знаком +
или -
, а за мнимой частью числа следует символ j
.
Вот примеры нескольких комплексных чисел: 3.5+2j
, 0.5j
, 4+0j
,
-1 - 3.7j
. Обратите внимание, что если действительная часть числа
равна 0
, ее можно вообще опустить.
Отдельные части комплексного числа доступны в виде атрибутов real
и imag
. Например:
>>> z = -89.5+2.125j
>>> z.real, z.imag
(-89.5, 2.125)
За исключением //
, %
, divmod()
и версии pow()
с тремя
аргументами все остальные арифметические операторы и функции,
перечисленные в табл. 1 могут использоваться для
работы с комплексными числами, так же как и соответствующие
комбинированные операторы присваивания. Кроме того, значения типа
complex
имеют метод conjugate()
, который изменяет знак мнимой
части. Например:
>>> z.conjugate()
(-89.5-2.125j)
>>> 3-4j.conjugate()
(3+4j)
Тип данных complex
может вызываться как функция – без аргументов
она вернет значение 0j
, с аргументом типа complex
она вернет копию
аргумента, а с аргументом любого другого типа она попытается
преобразовать указанный объект в значение типа complex
. При
использовании для преобразования функция complex()
принимает либо
единственный строковый аргумент, либо одно или два значения типа
float
.
Если ей передается единственное значение типа float
, возвращается
комплексное число с мнимой частью, равной 0j
.
Функции в модуле math
не работают с комплексными числами. Это
сделано преднамеренно, чтобы гарантировать, что пользователи модуля
math
будут получать исключения вместо получения комплексных чисел в
некоторых случаях.
Если возникает необходимость использовать комплексные числа,
можно воспользоваться модулем cmath
, который содержит комплексные
версии большинства тригонометрических и логарифмических функций,
присутствующих в модуле math, плюс ряд функций, специально
предназначенных для работы с комплексными числами, таких
как cmath.phase()
, cmath.polar()
и cmath.rect()
, а также
константы cmath.pi
и cmath.e
, которые хранят те же самые значения
типа float
, что и родственные им константы в модуле math
.
Decimal
Во многих приложениях недостаток точности, свойственный числам
типа float
, не имеет существенного значения, и эта неточность
окупается скоростью вычислений. Но в некоторых случаях предпочтение
отдается точности, даже в обмен на снижение скорости работы. Модуль
decimal
реализует неизменяемый числовой тип Decimal
, который
представляет числа с задаваемой точностью. Вычисления с участием
таких чисел производятся значительно медленнее, чем в случае
использования значений типа float
, но насколько это важно, будет
зависеть от приложения.
Чтобы создать объект типа Decimal
, необходимо импортировать модуль
decimal
. Например:
>>> import decimal
>>> a = decimal.Decimal(9876)
>>> b = decimal.Decimal("54321.012345678987654321")
>>> a + b
Decimal('64197.012345678987654321')