Вещественные числа — float
Главным отличием вещественных чисел от целых является наличие символа ".
" которая отделяет целую часть от дробной:
2.78 2.0 2. 0.78 .78
Причем обратите внимание на числа 2.
и .78
, т.е. если Python видит, что слева или справа от точки ничего нет, то он понимает, что либо целая либо дробная часть равна \(0\).
Другой отличительной чертой является необязательное наличие символа "e
" – экспоненты:
2.78e-1 2e10 2e+10 2e-10 0e0
Если на длину целых чисел не накладывается абсолютно никаких ограничений по величине, то с вещественными числами это не так. Что бы узнать информацию о числах типа float для компьютера на котором выполняется программа, можно воспользоваться командой sys.float_info
:
>>> import sys
>>> sys.float_info # вывод я отформатировал вручную
sys.float_info(max=1.7976931348623157e+308,
max_exp=1024,
max_10_exp=308,
min=2.2250738585072014e-308,
min_exp=-1021,
min_10_exp=-307,
dig=15,
mant_dig=53,
epsilon=2.220446049250313e-16,
radix=2,
rounds=1)
max
- максимальное представимое число;max_exp
- максимальня степень \(2\);max_10_exp
- максимальное число e, такое что10**e
находится в[min , max]
;min
- минимальное представимое число;min_exp
- минимальная степень \(2\);min_10_exp
- минимальное число e, такое что10**e
находится в[min , max]
;dig
- максимальное число цифр, которыми можно точно отобразить число;mant_dig
- максимальное число цифр в radix системе счисления, которыми можно точно отобразить число;epsilon
- разность между \(1\) и наименьшим числом большим \(1\) которую можно представить как число с плавающей точкой;radix
- основание используемой системы счисления;rounds
- целочисленная константа определяющая режим округления.
В данном выводе для нас представляют особый интерес значения: max
, min
, max_10_exp
и min_10_exp
, которые определяют пределы диапазонов для мантисы и степени, например:
>>> 10.0**308 # не приводит к ошибке
1e+308
>>> 10.0**309 # а это уже недопустимо
Traceback (most recent call last):
OverflowError: (34, 'Numerical result out of range')
Значения -inf, inf и nan
Тем не менее вместо ошибок OverflowError, когда число выходит за указанные пределы, иногда появляются значения -inf
и inf
:
>>> 1.7*10e307
1.7e+308
>>>
>>> 1.7*10e307*1.7*10e307
inf
>>>
>>> -10e9999
-inf
Возможно, к появляению ошибки OverflowError приводит только операция возведения в степень (скорее всего, хотя может я и не прав, точные причины возникновения данной ошибки кроются где-то в недрах языка C, на котором реализован интерпретатор CPython). Все что нужно знать о значениях -inf
и inf
это то что это числа обозначающие плюс минус бесконечность. Да, это на самом деле числа числа с плавающей запятой, которые могут учавствовать в выражениях:
>>> inf = 10e777
>>> inf**3000
inf
>>> inf - 3000
inf
Однако, что бы вы не делали с бесконечностью, она так и останется бесконечностью. Единственное что можно попробовать, так это вычесть из одной бесконечности другую бесконечность:
>>> inf - inf
nan
И мы получили nan
- значение, которое означает неопределяемое число (или "не число"). Но оно ведет себя как число, и в каком бы выражении оно не появилось, результат всегда будет nan
(кроме nan/0
т.к. деление на \(0\) всегда приводит к появлению ошибки):
>>> 2*nan + 1
nan
>>>
>>> -inf*inf*nan
nan
В реальной жизни, вы скорее всего никогда не встретитесь с значениями -inf
, inf
и nan
, если только не собираетесь заниматься какими-нибудь весьма специфичными вычислениями. Но, как правило, тех, кто встречается с этими значениями впервые, почему-то смущает, то что они не понимают откуда берутся и как действуют эти значения.
Арифметические операции
Целые числа поддерживают следующие математические операции, которые отсортированы по убыванию приоритета:
№ | Операция | Результат | Замечание |
---|---|---|---|
1 | x ** y |
возводит x в степень y | (I) |
2 | pow(x, y[, z]) |
возводит x в степень y по модулю z, где z – необязательный аргумент | (I) |
3 | divmod(x, y) |
возвращает кортеж с парой чисел (x // y, x % y) |
(II) |
4 | x.conjugate() |
возвращает \(\bar{x}\) - число, которое комплексно сопряжено с \(x\) | |
5 | complex(re, im) |
преобразует re в комплексное число (по умолчанию im = 0 ) |
(V) |
6 | float(x) |
преобразует x в вещественное число (число с плавающей точкой) | (V) |
7 | int(x) |
переобразует x в целое число, представленное в десятичной системе счисления | (V) |
8 | abs(x) |
абсолютное значение (модуль) числа x | |
9 | +x |
делает число x положительным | |
10 | -x |
делает число x отрицательным | |
11 | x % y |
остаток от деления x на y | (II) |
12 | x // y |
результат целочисленного деления x на y | (III) (II) |
13 | x / y |
результат "истинного" деления x на y | |
14 | x * y |
произведение x и y | |
15 | x - y |
разность x и y | |
16 | x + y |
сумма x и y |
Важно: приоритет математических операций выше побитовых логических операций и операций сравнения.
Замечания:
I. возведение \(0\) в степень \(0\) возвращает \(1\):
>>> 0**0, pow(0, 0)
(1, 1)
Извлечение корней четной степени из отрицательных чисел не вызывает ошибки, а возвращает комплексное число:
>>> (-0.1)**0.5
(1.9363366072701937e-17+0.31622776601683794j)
>>>
>>> pow(-3.14, 1/4)
(0.9412769291411894+0.9412769291411892j)
Использование в выражении x ** y
слишком больших значений x и y типа float
может привести к ошибке OverflowError.
II. функция divmod()
и операции %
, //
не работают для комплексных чисел. Для вас это может быть и очевидно, но не пользователя для которого вы пишите программу.
III. Данная операция всегда возвращает целое число, т.е. если число x можно представить в виде d*y + r
, то x//y = d
(r – остаток от деления). Так же следует иметь ввиду, что результат данной операции всегда округляется в сторону минус бесконечности:
>>> 0.1//0.2, (-0.1)//0.2, 0.1//(-0.2), (-0.1)//(-0.2)
(0.0, -1.0, -1.0, 0.0)
Это немного сбивает с толку, но проверив результат по формуле x = d*y + r
, вы убедитесь что все верно.
IV. встроенная функция int()
отбрасывает дробную часть вещественных чисел:
>>> int(3.14), int(-3.14)
(3, -3)
V. строго говоря эти функции не являются математическими, но они могут учавствовать в математических выражениях Python и поэтому должны обладать приоритетом.
Операции сравнения
Для сравнения чисел, доступно \(8\) операций сравнения, причем все они имеют одинаковый приоритет:
№ | Операция | Результат | Замечание |
---|---|---|---|
1 | x < y |
True если x меньше y, иначе False | |
2 | x <= y |
True если x меньше или равно y, иначе False | |
3 | x > n |
True если x больше y, иначе False | |
4 | x >= n |
True если x больше или равно y, иначе False | |
5 | x == y |
True если x равно y, иначе False | |
6 | x != y |
True если x не равно y, иначе False | |
7 | x is y |
True если x и y это один и тот же объект, иначе False | |
8 | x is not y |
True если x и y это не один и тот же объект, иначе False |
Важно: приоритет операций сравнения ниже математических и побитовых операций.
Важно: числа типа float не являются десятичными дробями и используют двоичную арифметику компьютера, поэтому многие, даже самые простые выражения могут вычисляться с ничтожно малыми погрешностями. Однако, из-за этих погрешностей, вполне очевидные операции сравнения работают не так как ожидается:
>>> 0.7 - 0.4 - 0.3 == 0 # должно быть True, но получаем:
False
>>>
>>> 0.7-0.4-0.3 # потому что результат выражения не равен 0
-5.551115123125783e-17
В Python сравнение x > y and y > z
является эквивалентным x > y > z
т.е. сравнения связаные оператором and
в произвольные цепочки могут быть записаны в более компактной форме. Выполнение таких выражений начинается слева направо и останавливается как только будет получено первое значение False. Это означает, что если в выражении x > y > z
сравнение x > y
вернет False то сравнение y > z
выполняться не будет.
Методы вещественных чисел
Вещественные числа – это объекты, которые обладают следующими методами:
- float.as_integer_ratio()¶
- возвращает пару целых чисел (кортеж), первое из которых равно числителю а второе всегда положительному знаменателю обыкновенной дроби, значение которой точно совпадает с указанным исходным числом типа float:
>>> (0.3).as_integer_ratio()
(5404319552844595, 18014398509481984)
Появление таких больших чисел связано с тем, что числа типа float на самом деле не являются десятичными дробями, и хранятся в памяти с небольшой погрешностью:
>>> 5404319552844595/18014398509481984
0.3
>>> from decimal import *
>>>
>>> Decimal(5404319552844595)/Decimal(18014398509481984)
Decimal('0.2999999999999999888977697537')
- float.is_integer()¶
- возвращает True если дробная часть числа равна \(0\) и False если нет:
>>> (3.0).is_integer()
True
>>> (3.14).is_integer()
False
Python позволяет преобразовывать вещественные числа из десятичной системы счисления в шестнадцатеричную и обратно. Создание вещественных чисел из их шестнадцатеричного представления, позволяет избежать погрешности которая неминуемо возникает при переводе десятичных чисел в двоичное представление. Шестнадцатеричные вещественные числа в Python задаются строкой вида:
[sign] ['0x'] integer ['.' fraction] ['p' exponent]
где sign
– это необязательный знак, который может быть как +
или -
; integer
– и fraction
– целая и дробная части которые должны обязательно содержать хотя бы по одной цифре, '0x'
– уже знакомый нам префикс, обозначающий шестнадцатеричные числа и 'p' exponent
– экспонента в виде десятичного целого числа со знаком или без.
Показатель степени 'p' exponent
является степенью двойки, например, перевод числа '0x2.f1ap+3'
из шестнадцатеричной системы счисления в десятичную будет выглядеть следующим образом:
>>> (2 + 15./16 + 1./16**2 + 10./16**3)*2**3
23.55078125
Применение обратного преобразования дает другую шестнадцатеричную строку, которая, однако, представляет тоже самое число:
>>> (_).hex()
'0x1.78d0000000000p+4'
>>>
>>> (1 + 7./16 + 8./16**2 + 13./16**3)*2**4
23.55078125
- float.hex()¶
- возвращает представление числа в шестнадцатеричной системе счисления:
>>> (3.141592).hex()
'0x1.921fafc8b007ap+1'
>>>
>>> (10.01).hex()
'0x1.4051eb851eb85p+3'
- classmethod float.fromhex(s)¶
- метод класса для преобразования шестнадцатеричной строки s в число типа float:
>>> float.fromhex('0x1.4051eb851eb85p+3')
10.01
>>>
>>> # строка может иметь начальные и конечные пробельные символы:
... float.fromhex(' 0x1.921fafc8b007ap+1 ')
3.141592
>>>
>>> float.fromhex('0x0.1p+3')
0.5
>>> float.fromhex('0x0.31p+1')
0.3828125