Mathematic in python
Помимо встроенных типов чисел предоставляется дополнительные классы для вычислений с повышеннйо точностью или специальных вычислений.
decimal
Числа с фиксированной точностью и числа с плавающей точкой.
Десятичное число в данном модуле - это неизменяемый тип данных. Десятичное число может обладать знаком, состоять из мантисы и экспоненты. Для сохранения значимости конечные нули не усекаются.
Контекст вычислений определяет точность, правила округления, ограничения на экспоненты, флаги результатов операций и средства активации исключений.
Сигналы – это специальные условия, которые возникают в процессе вычислений и могут использоваться для вызова исключений.
Дробные десятичные числа представлены классом Decimal
. Его конструктору передается одно целое число или строка. Можно использовать from_float()
для точного преобразования числа с плавающей точкой. В последнем случае длина строки может быть значительной, так как некоторые числа с плавающей точкой невозможно точно представить в двоичной форме.
import decimal
>>> print(decimal.Decimal(5))
5
>>> print(decimal.Decimal('3.14'))
3.14
>>> print(decimal.Decimal(str(0.1)))
0.1
>>> print(decimal.Decimal.from_float(0.1))
0.1000000000000000055511151231257827021181583404541015625
Кроме того, дробное десятичное число можно задать как кортеж, содеоржащий флаг знака (0 для пложительных, 1 для отрицательных), кортеж цифр и целочисленную экспоненту.
>>> m = (1, (1, 1, 1), -4)
>>> print(decimal.Decimal(m))
-0.0111
Над decimal можно производить теже арифметические операции, что и над стандартными числовыми типами. При этом поддерживаются и арифметические операции с целочисленными типами… а вот числа с плавающей точкой должны быть предварительно преобразованы в decimal.
Decimal
предоставляет специальные числовые типы Infinity
, NaN
и 0
. Сравнение с NaN
на равенство всегда возвращает False
, а на неравенство - True
. При этом сравниваться в целях сортировки нельзя - будет поднята ошибка. Оба типа могут иметь знак + и -.
>>> import decimal
>>> for value in ['Infinity', 'NaN', '0']:
>>> print(decimal.Decimal(value), decimal.Decimal('-' + value))
Infinity -Infinity
NaN -NaN
0 -0
Полный синтаксис
sign ::= '+' | '-'
digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
indicator ::= 'e' | 'E'
digits ::= digit [digit]...
decimal-part ::= digits '.' [digits] | ['.'] digits
exponent-part ::= indicator [sign] digits
infinity ::= 'Infinity' | 'Inf'
nan ::= 'NaN' [digits] | 'sNaN' [digits]
numeric-value ::= decimal-part [exponent-part] | infinity
numeric-string ::= [sign] numeric-value | [sign] nan
Способ округления и точность decimal можно задать с помощью контекста
>>> import decimal
>>> decimal.getcontext()
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999,
capitals=1, clamp=0, flags=[], traps=[Overflow, DivisionByZero,
InvalidOperation])
>>> decimal.getcontext().prec = 7 # Set a new precision
Точность задается через атрибут prec
, который можно установить в диапазоне от 1 до decimal.MAX_PREC
Округление задается через атрибут rounding
. Доступно несколько опций:
ROUND_CEILING
округлять в направлении бесконечностиROUND_DOWN
в направлении 0ROUND_FLOOR
в направлении минус бесконечностиROUND_HALF_DOWN
если последняя цифра >=5 в направлении от 0, в противном случае к 0ROUND_HALF_EVEN
если последняя цифра ==5, проверить предпоследнюю. Четные цифры приводят к округлению вниз. нечетные - вверхROUND_HALF_UP
аналогично down с той лишь разницей, что >5ROUND_UPROUND_05UP
от нуля, если последняя цифра 0 или 5, в остальных случаях к 0
Что-бы не менять весь контекст, контекст можно задать локально через менеджера:
from decimal import localcontext
with localcontext() as ctx:
ctx.prec = 42 # Perform a high precision calculation
s = calculate_something()
s = +s # Round the final result back to the default precision
Кроме того, контексты можно использовать для создания экземпляра Decimal
, который унаследует все вводные, взятые из контекста.
>>> import decimal
>>> c = decimal.getcontext().copy()
>>> c.prec = 3
>>> pi = c.create_decimal('3.1415')
>>> print('PI:', pi)
PI: 3.14
>>> print('RESULT:', decimal.Decimal('2.01') * pi)
RESULT: 6.3114
На самом деле глобальный контекст в decimal является локальным контекстом потока, поэтому каждый поток может конфигурироваться с использованием разных значений. Кроме того, с помощью сигналов можно устанавливать недопустимые операции, при выполнении которых будет поднята ошибка.
Пример с тредами на gists:
fractions
Определяет операции, осуществляемые над числами из множества рациональных чисел. Апи определено классом Rational
в модуле numbers
. fractions
полностью поддерживает все математические выражения
Есть несколько способов создания fractions
. Во первых непосредственно задав числитель и знаменатель
>>> from fractions import Fraction
>>> f = Fraction(1, 4)
>>> print(f)
1/4
Второй вариант - использование строкового представлениия “числитель/знаменатель”. Поддерживаются также любые строки, которые могут быть преобразованы во float()
>>> f = Fraction('1/4')
>>> f = Fraction('0.5')
>>> f = Fraction('5e-3')
Кроме того можно создавать экземпляры Fraction
непосредственно из float
или Decimal
. При этому потери точности, как в Decimal
уже нет. Однако значения с плавающей точкой, которые не могут быть выражены точно в Decimal
могут привести к очень большим дробям во Fraction
.
>>> f = Fraction(0.1)
>>> print(f)
3602879701896397/36028797018963968
Есть способ этим управлять, устанавливая предельный размер значения знаменателя
>>> print(f.limit_denominator(10))
1/10
random
Модуль предоставялет генератор псевдослучайных чисел. основанный на Mersenne twister алгоритме. Числа, получаемые таким методом, подчиняются равномерному распределению с большим периодом повторения.
Функция random()
возвращает следующее число из генерируемой последовательности. Все значения последовательности принадлежат [0, 1.0). Естественно повторные запуски приводят к разным последовательностям.
uniform()
позволяет сгенерировать число из выбранного интервала. В данном случае просто происходит корректировка возврата из random()
по формуле min + (max - min) * random
>>> import random
>>> print(random.uniform(1, 100))
25.113356610778503
Чтобы не получать каждый раз разные последовательности случайных чисел, генератор можно инициализировать функцией seed()
. Сид влияет на генерацию первого числа последовательности, а с учетом ее детерменированности, по сути на всю последовательность. Если сид не задан, используется фактор определяющий случайность, специфичный для платформы или, если такого нет, системное время.
Кроме того, состояние генератора случайных чисел можно сериализовать. При загрузке состояния, оно будет выступать в качестве начальтной точки для продолжения процесса генерации, чято снижает вероятность получения ранее полученных значений. Все это делается с помощью getstate()
и setstate()
Случайное целое число можно получить с помощью randint()
, указав соответствующий диапазон генерации. Числа могут быть положительные и отрицательные, первое меньше второго. randrange()
реализует выбор из диапазона с шагом.
choice()
позволяет выбрать случайный элемент из последовательности. См. статью [random-choice]
>>> import random
>>> outcomes = {
... 'heads': 0,
... 'tails': 0,
... }
>>> sides = list(outcomes.keys())
>>> for i in range(10000):
outcomes[random.choice(sides)] += 1
>>> print('Heads:', outcomes['heads'])
Heads: 4932
>>> print('Tails:', outcomes['tails'])
Tails: 5068
Функция shuffle()
реализует случайный выбор с перемешиванием на месте. sample()
- реализует случайную выборку без возврата (получается список элементов заданной длины без повторов). Работает только с хешируемыми объектами и, соответственно, исходную последовательность не изменяет.
Инициалищзировав класс Random
можно задать несколько состояний нескольких генераторов и управлять процессами рандомизации по отдельности. Использование системного времени ожидаемо привело к генерации одного и того же значения.
>>> import random
>>> import time
>>> seed = time.time()
>>> r1 = random.Random(seed)
>>> r2 = random.Random(seed)
>>> for i in range(3):
... print('{:04.3f} {:04.3f}'.format(r1.random(), r2.random()))
0.481 0.481
0.911 0.911
0.324 0.324
Можно получить доступ к системному генератору случайных чисел через класс SystemRandom
>>> import random
>>> import time
>>> seed = time.time()
>>> r1 = random.SystemRandom(seed)
>>> r2 = random.SystemRandom(seed)
>>> for i in range(3):
... print('{:04.3f} {:04.3f}'.format(r1.random(), r2.random()))
0.379 0.351
0.625 0.157
0.508 0.405
В данном слкчае seed()
уже ничего не задает, т.к. используется системный рандомизатор.
Наконец, random
включает несколько функций, позволяющих получать случайные числа не только из однородного распределения:
- нормальное распределение
- логнормальное (логарифмы распределены нормально) распределение
- аппроксимирующее распределение
- экспоненциальное распределение
- круговое нормальное распределение
- бета-распределение, гамма-распределение и распределение Вейбулла
подробнее смотри тут
math
Математические константы и функции. Модуль поставляет ряд собственных констант, в т.ч. определяющих бесконечные числа (inf), возникающие в результате переполнения разрядов и неопределенное значение (nan).
>>> import math
>>> print('{:.30f}'.format(math.pi))
3.141592653589793115997963468544
>>> print('{:.30f}'.format(math.e))
2.718281828459045090795598298428
>>> print('{:.30f}'.format(math.nan))
nan
>>> print('{:.30f}'.format(math.inf))
inf
Часть операций приводят не к значениям inf
, а к ошибке OverflowError
- это связано с реализацией на C. Деление с участием бесконечных значений приводит к nan
, который не равен никакому другому значени в т.ч. и себе. Самый простой способ проверить - функции isnan()
и isfinite()
.
Сравнение чисел с плавающей точкой подвержены ошибкам представления числа. С помощью isclose()
можно минимизировать вероятность ошибки представления. Этот метод позволяет стравнивать с определенным допуском и. естественно, не гарантирует точное соответствие. nan
не может быть близким ни к одному значению, вклюяая самого себя. inf
близок только к самому себе.
Числа с плавающей точкой можно преобразовать в целые трямя способами. trunc()
отбрасывает дробную часть (эквивалентно непосредственному преобразованию). floor()
округляет до наибольшего из предшествующих целых, ceil()
до наименьшего.
modf()
преобразует число с плавающей точкой в кортеж, где первое значение - цклая часть, а второе - дробная. Оба числа в кортеже - с плавающей точкой.
frexp()
возвращает мантиссу и экспоненту числа с плавающей точкой: x=m*2^e - возвращается m и e. Это можно использовать для переноса значений между системами. ldexp()
осуществляет обратное преобразование.
fabs()
возвращает абсолютное значение (число без знака). copysign()
возвращает знак числа. что полезно для сравнения с nan
, у которого тоже может быть знак.
fsum()
реализуют более точный алгоритм вычисления суммирования над числами с плавающей точкой.
factorial()
повзволяет вычислить факториал для целых чисел или для чисел с плавающей точкой, если те могут быть преобразованы в целые без потери точности.
gamma()
считает гаммафункцию, а lgamma()
ее натуральный логарифм.
fmod()
предоставляет более точную реализацию деления по модулю, чем % для чисел с плавающей точкой. Знак результата может отдличаться из-ща отличий в реализации.
gcd()
наибольший общий делитель
pow()
возводит в степень (возвращает float). sqrt()
отдельно реализует квадратный корень. При этом math
не работает с комплексными числами и корень из отрицательного числа ведет к ValueError
log()
натуральный логарифм. log10()
реализует более точный алгоритм для десятичного логарифма. log2()
для логарифма по основанию 2. log1p()
вычисляет ряд Ньютона-Меркатора и более точен для значений, близких к 0.
exp()
экспонента. exp1p()
возвращает e^(x)-1
Градусы переводятся в радианы с помощью radians()
. Обратно - degrees()
. Тригонометрические функции (в радианах): sin()
, cos()
, tan()
. Гипотянуза hypot()
. Обратные ф-ии: asin()
, acos()
, atan()
. Гиперболические функции: sing()
, cosh()
, tanh()
, asing()
, acosh()
, atanh()
.
Реализовано несколько специальных функций. Гауссова ф-ия ошибок erf()
и erfc()
(1 - erf).
В модуле statistics
реализованы статистические функции для int
, float
, Decimal
, Fraction
: mode()
, mean()
, median()
(median_low()
, median_high()
для устранения скошенности статистики из-за числа элементов набора данных), median_grouped()
, а также методы для расчета дисперсии и мат.ожидания для генеральной совокупности и выборок. Еще можно считать корреляции. ковариации и лин.регрессию. Подробнее тут
Документация модуля math. Некоторео кол-во функций добавлено после 3.8
Смотри еще: