6 способов найти модуль числа в Python 3 — Юрыч BRO на vc.ru
Вступление
8511 просмотров
Всем начинающим кодерам привет!
Модуль числа… Это, казалось бы, простая вещь… да, так оно и есть. Тем не менее — всегда интересно поэкспериментировать и по-новому взглянуть на простое.
Сегодня я покажу вам 6 способов найти модуль числа в Python 3. Я не стал добавлять сюда совсем абсурдные вещи, но немного абсурдности здесь все же будет.
1 способ
Для начала самое очевидное. Проверяем отрицательное число (назовем его x) или положительное, т.е. <0 или нет. В случае отрицательного значения x, его нужно умножить на -1. Можно так:
def abs1(x): if x < 0: return x*(-1) return x
А можно заменить умножение унарным минусом:
def abs1(x): if x < 0: return -x return x
2 способ
Самое короткое решение в нашей статье — найти максимум между x и -x. Таким образом результат всегда будет положительным:
def abs2(x): return max(-x, x)
3 способ
Здесь мы проверяем строку на наличие в ней минуса. Изначально я хотел использовать метод isdigit(), но потом я понял, что метод не считает точку частью числа, поэтому для float в строке метод возвращает False. Поэтому:
def abs3(x): if ‘-‘ in str(x): return -x return x
4 способ
Этот способ использует условную инструкцию из предыдущей функции, но использует срез, чтобы избавиться от минуса. 3 строка выглядит не очень, приходится дважды менять тип данных результата. По-моему — это ухудшенная версия 3 способа:
def abs4(x): if ‘-‘ in str(x): return float(str(x)[1::]) return x
5 способ
Тут мы будем использовать факт того, что операция квадратного корня в Python всегда возвращает положительный результат. Эту операцию не обязательно брать из библиотеки Math, можно просто возвести число в с степень 0.
5. Итак:def abs5(x): return (x*x)**0.5
6 способ
Здесь мы используем операции со строками, как в 4 способе. Отличие в том, что мы не проверяем строку на наличие минуса. Мы убираем уго, есть он в строке или нет. Метод replace() позволяет убрать все повторения одного символа, что для нас избыточно, но с нулем повторений он тоже работает:
def abs6(x): return float(str(x).replace(‘-‘, »))
Примечание: говоря про положительные значения, правильнее сказать — положительные или нулевые, но я решил не засорять текст такой мелочью.
Статистика быстродействия
Подведем итоги, узнаем — что же быстрее работает. О том, как замерить время работы программы, я, возможно, расскажу в одной из следующих статей. Ну а пока что приведу статистические данные.
Я измерил время работы данного куска кода, где i — одна из 6 функций.
for j in range(100000): a = (i(1), i(-1), i(1.0), i(-1.0))
И вот что получилось:
Что у нас по итогу? Худший результат показал 4 способ, неудивительно. Самый очевидный способ — первый, на 2 месте. С большим отрывом лидирует 5 вариант, 100000 повторений за 0.79 сек! Математика быстрее логического оператора if и операций со строками.
Заключение
Я надеюсь, что вам была интересна данная статья, и вы разобрались в теме. Если хотите меня дополнить — пишите в комментариях. Удачи в мире IT!
Модуль числа в Python – abs и fabs
upd:
Александр Зайков
14.2K
1
Содержание:развернуть
Запускаю китайскую реплику «ТАРДИС», и вот мы в пятом классе. На доске нарисована числовая ось, а на ней выделен отрезок. Его начало в точке 4, а конец — в 8. Учительница говорит, что длину отрезка можно найти путём вычитания координаты начала отрезка из координаты его конца. Вычитаем, получаем 4, и радуемся — мы нашли длину. Ура! 🎉
Перемещаемся на год вперёд, и там происходит странное: учительница выделяет мелом другой отрезок, но делает это в каком-то неправильном месте — левее точки с цифрой «0». Теперь перед нами старая задача, но с новыми числами и даже буквами: A, B, минус 4 и минус 8. Мы начинаем искать длину отрезка AB = [-4;-8]:
Переводим непонимающий взгляд с получившейся отрицательной длины на довольную улыбающуюся учительницу, а затем на доску. Там наверху, рядом с сегодняшней датой, написана тема урока: «Модуль числа».
Что такое модуль числа
Теперь по-взрослому.
Модуль числа называют абсолютной величиной.
Для вещественных чисел модуль определяется так:
Формула модуля числа для вещественных чиселТ.е. в любом случае, модуль — число большее или равное 0. Поэтому отрицательная длина в примере хитрой учительницы должна была быть взята по модулю:
Тогда дети бы увидели, что геометрический смысл модуля — есть расстояние. Это справедливо и для комплексных чисел, однако формальное определение для них отличается от вещественного:
, где z — комплексное число: z = x + iy.
В Python для нахождения модуля числа применяются две функции: fabs()
из подключаемой библиотеки math
и встроенная функция abs()
.
Abs
В то время как math.fabs()
может оперировать только вещественными аргументами, abs()
отлично справляется и с комплексными. Для начала покажем, что abs
в python работает строго в соответствии с математическим определением.
# для вещественных чисел
print(abs(-1))
print(abs(0))
print(abs(1))
> 1
> 0
> 1
Как видно, с вещественными числами всё в порядке. Перейдём к комплексным.
# для комплексных чисел
print(complex(-3, 4))
print(abs(complex(-3, 4)))
> (-3+4j)
> 5.0
Если вспомнить, что комплексное число выглядит так: z = x + iy, а его модуль вычисляется по формуле:
, то можно без труда посчитать, что sqrt(3**2 + 4**2)
действительно равно 5.0
.
Можно заметить, что abs()
возвращает значения разных типов. Это зависит от типа аргумента:
print(type(abs(1)))
> <class 'int'>
print(type(abs(1.0)))
> <class 'float'>
print(type(abs(complex(1. 0, 1.0))))
<class 'float'>
В этом кроется ещё одно отличие abs()
от
. Функция из модуля math
всегда приводит аргумент к вещественному типу, а если это невозможно сделать — выбрасывает ошибку:
print(type(math.fabs(complex(2,3))))
> TypeError: can't convert complex to float
Fabs
Для начала работы с fabs()
необходимо импортировать модуль math
с помощью следующей инструкции:
import math
Мы уже выяснили, что fabs()
не работает с комплексными числами, поэтому проверим работу функции на вещественных:
print(math.fabs(-10))
print(math.fabs(0))
print(math.fabs(10))
> 10.0
> 0.0
> 10.0
Функция производит вычисления в соответствие с математическим определением, однако, в отличие от abs()
, всегда возвращает результат типа float
:
print(type(math.fabs(10)))
> <class 'float'>
Основные свойства модулей
# Квадрат модуля = квадрату числа
print(pow(4, 2) == pow(abs(4), 2))
> True
# |x| = |-x|
print(abs(-10) == abs(10))
> True
# Модуль произведения = произведению модулей: |ab|=|a||b|
print(math. fabs(11 * 3) == math.fabs(11) * math.fabs(3))
> True
# Аналогично для деления: |a/b|=|a|/|b|
print(math.fabs(48/8) == math.fabs(48) / math.fabs(8))
> True
# |a ** b| = |a| ** b
print(abs(2 ** 10) == abs(2) ** 10)
> True
И еще несколько важных неравенств:
- m <= |m|
- -|m| <= m
- |m| >= 0
- |m + n| <= |m| + |n|
- |m – n| <= |m| + |n|
- |m| — |n| <= |m + n|
- |m + n| >= ||m| — |n||
- |m – n| >= ||m| — |n||
чисел — Числовые абстрактные базовые классы — Документация по Python 3.11.3
Исходный код: Lib/numbers.py
Модуль номеров
( PEP 3141 ) определяет иерархию числовых
абстрактные базовые классы, которые постепенно определяют
больше операций. Ни один из типов, определенных в этом модуле, не предназначен для создания экземпляров.
- класс номеров.Номер
Корень числовой иерархии. Если вы просто хотите проверить, является ли аргумент x — это число, неважно, какого рода, используйте
isinstance(x, Number)
.
Числовая башня
- класс номеров.Комплекс
Подклассы этого типа описывают комплексные числа и включают операции которые работают на встроенном комплексе
типа
. Это: преобразования всложный
илогический
,реальный
,образ
,+
,-
,*
,/
,**
,абс()
,сопряженное()
,==
, и!=
. Все, кроме-
и!=
, являются абстрактными.- настоящий
Реферат. Извлекает действительную составляющую этого числа.
- изображение
Реферат. Извлекает мнимую составляющую этого числа.
- абстрактный метод сопряженный ()
Реферат. Возвращает комплексное сопряжение. Например,
(1+3j).conjugate() == (1-3j)
.
- класс номеров.Настоящий
К
Complex
,Real
добавляет операции, которые работают с реальными числа.Короче говоря, это: преобразование в
float
,math.trunc()
,round()
,math.floor()
,math.ceil()
,divmod()
,//
%
,<
,<=
,>
и>=
.Real также предоставляет значения по умолчанию для
complex()
,real
,imag
иconjugate()
.
- класс номеров.Rational
Подтипы
Действительное
и добавляетчислитель
изнаменатель
свойств. Он также обеспечивает значение по умолчанию дляс плавающей запятой()
.Числитель
знаменатель
значений должны быть экземплярамиIntegral
и должны быть в наименьших условиях сзнаменатель
положительный.- числитель
Реферат.
- знаменатель
Реферат.
- класс номеров. Интеграл
Subtypes
Rational
и добавляет преобразование в 9,|
,~
.
Примечания для разработчиков типа
Разработчики должны быть осторожны, чтобы сделать равные числа равными и хешировать
их к одним и тем же значениям. Это может быть тонко, если есть два разных
расширения действительных чисел. Например, дроби . Дробь
реализует hash()
следующим образом:
по определению __hash__(я): если self.знаменатель == 1: # Получить целые числа правильно. хэш возврата (self. numerator) # Дорогая проверка, но точно правильная. если я == поплавок (я): вернуть хэш (с плавающей запятой (сам)) еще: # Используйте хэш кортежа, чтобы избежать высокой частоты коллизий на # простые дроби. хеш возврата((self.numerator, self.denominator))
Добавление дополнительных числовых ABC
Есть, конечно, и другие возможные азбуки для чисел, и это было бы
быть плохой иерархией, если она исключает возможность добавления
те. Вы можете добавить MyFoo
между Complex
и Реальный
с:
класс MyFoo (комплекс): ... MyFoo.register(Настоящий)
Реализация арифметических операций
Мы хотим реализовать арифметические операции так, чтобы смешанный режим
операции либо вызывают реализацию, автор которой знал о
типы обоих аргументов или преобразовать оба в ближайший встроенный тип
и сделать операцию там. Для подтипов Интеграл
, это
означает, что __add__()
и __radd__()
должны быть определены как:
класс MyIntegral(Integral): def __add__(я, другой): если isinstance (другое, MyIntegral): вернуть do_my_adding_stuff(я, другой) elif isinstance (другое, OtherTypeIKnowAbout): вернуть do_my_other_adding_stuff(я, другой) еще: вернуть нереализованный def __radd__(я, другой): если isinstance (другое, MyIntegral): вернуть do_my_adding_stuff(другое, себя) elif isinstance (другое, OtherTypeIKnowAbout): вернуть do_my_other_adding_stuff(другое, себя) elif isinstance (другой, интеграл): вернуть int(другое) + int(себя) elif isinstance (другое, реальное): вернуть поплавок (другой) + поплавок (сам) elif isinstance (другой, сложный): вернуть комплекс (другой) + комплекс (я) еще: вернуть нереализованный
Существует 5 различных случаев для операции смешанного типа над подклассами Комплекс
. Я буду ссылаться на весь приведенный выше код, который не
см. MyIntegral
и OtherTypeIKnowAbout
как
«шаблон». a
будет экземпляром A
, который является подтипом
Комплекс
( a : A <: Комплекс
) и b : B <:
Комплекс
. Я рассмотрю a + b
:
Если
А
определяет__add__()
который принимаетb
, все хорошо.Если
A
возвращается к стандартному коду, вернуть значение из__add__()
, мы бы упустили возможность чтоB
определяет более интеллектуальный__radd__()
, поэтому шаблон должен возвращатьNotImplemented
из__добавить__()
. (Илиможет не реализовать
__add__()
в все.)Затем
B
__radd__()
получает шанс. Если он принимаети
, все хорошо.Если он возвращается к шаблону, больше нет возможных методы, чтобы попробовать, так что это где реализация по умолчанию должен жить.
Если
B <: A
, Python пытается использоватьB.__radd__
доА.__добавить__
. Это нормально, потому что это было реализовано с помощью знаниеA
, поэтому он может обрабатывать эти экземпляры до делегированиеКомплекс
.
Если A <: Сложные
и B <: Действительное
без обмена какими-либо другими знаниями,
тогда подходящей общей операцией является операция, включающая встроенный
в комплексе
, и оба __radd__()
приземляются там, поэтому a+b
== б+а
.
Поскольку большинство операций над любым данным типом будут очень похожими,
может быть полезно определить вспомогательную функцию, которая генерирует
прямые и обратные экземпляры любого заданного оператора. Например, дробей.Дробь
использует:
по определению _operator_fallbacks (мономорфный_оператор, резервный_оператор): защита вперед (а, б): если isinstance(b, (int, Fraction)): вернуть monomorphic_operator(a, b) elif isinstance(b, float): вернуть fallback_operator (с плавающей запятой (а), б) elif isinstance (b, комплекс): вернуть fallback_operator (комплекс (а), б) еще: вернуть нереализованный forward.__name__ = '__' + fallback_operator.__name__ + '__' вперед.__doc__ = мономорфный_оператор.__doc__ деф реверс(б, а): если isinstance(a, Rational): # Включает целые числа. вернуть monomorphic_operator(a, b) elif isinstance(a, Real): return fallback_operator (с плавающей запятой (a), с плавающей запятой (b)) elif isinstance(a, Комплекс): return fallback_operator (комплекс (а), комплекс (б)) еще: вернуть нереализованный reverse. __name__ = '__r' + резервный_оператор.__name__ + '__' reverse.__doc__ = monomorphic_operator.__doc__ возврат вперед, назад определение _add (а, б): """а + б""" return Fraction (a.числитель * b.знаменатель + б.числитель * а.знаменатель, а.знаменатель * б.знаменатель) __add__, __radd__ = _operator_fallbacks(_add, operator.add) # ...
Python Numbers — неофициальная документация по разработке Python (заметки Виктора)
float
: число с плавающей запятой, обычно IEEE 754 (64 бита, основание 2) сложный
: комплексный номер, реализованный как два числа с плавающей запятой decimal.Decimal
: число с плавающей запятой, хранящееся в базе 10, произвольное
точность дроби.Дробь
: рациональная, числитель/знаменатель; автоматически
вычислить наибольший общий делитель (НОД), чтобы упростить дробьЧисловая башня
Модуль чисел определяется PEP 3141 — Иерархия типов для чисел.
- номера.Номер: базовый класс
- числа. Комплекс: добавить
реальных
,изображений
,сопряженных ()
- номера. Real: подкласс Complex; добавить много операций с плавающей запятой.
- номера. Rational: подкласс Real; добавить
числитель
изнаменатель
атрибуты - номера. Интеграл: подкласс Rational
Подклассы:
- числа.Числа: целочисленные, с плавающей запятой, комплексные, десятичные.Десятичные, дробные.Дробь
- чисел. Комплекс: целое, число с плавающей запятой, комплекс, дроби. Дробь
- числа. Вещественное число: целое число, число с плавающей запятой, дроби. Дробь
- числа. Рациональное: целое, дроби. Дробь
- числа. Интеграл: int
int, float, сложные методы и атрибуты:
-
conjugate()
-
изображение
-
реальный
Атрибуты целого числа и дроби:
-
знаменатель
-
числитель
Преобразования в Python
int(obj)
и float(obj)
accept:
-
int
-
поплавок
-
десятичный. Десятичный
-
дроби.Дробь
-
байт
-
ул
int(obj)
округляет до нуля (ROUND_DOWN, например: int(0.9) == 0
и int(-0.9) == 0
).
Но int(obj)
и float(obj)
reject:
-
комплекс
комплекс(объект)
принимает:
-
инт
-
поплавок
-
комплекс
-
десятичный. Десятичный
-
дроби. Фракция
-
ул
Но комплекс(объект)
отклоняет:
-
байт
decimal.Decimal(obj)
принимает:
-
int
-
поплавок
-
десятичный. Десятичный
-
ул
Но decimal. Decimal(obj)
отклоняет:
-
комплекс
-
дроби. Фракция
-
байт
дроби. Фракция (объект)
принимает:
-
целое число
-
поплавок
-
десятичный. Десятичный
-
дроби.Дробь
-
стр.
(например:"1"
или"1/2"
)
Но дроби. Фракция(объект)
отбраковывает:
-
сложный
-
байт
тип int
Примеры:
>>> (123).bit_length() 7 >>> sys.int_info sys.int_info (bits_per_digit = 30, размер_цифры=4)
Сериализация в байтах:
>>> (123).to_bytes(4, 'маленький') б'{\х00\х00\х00' >>> int.from_bytes(b'{\x00\x00\x00', 'маленький') 123
Округление:
-
int(float)
вызываетfloat. __trunc__()
, поэтому округление до нуля (ОКРУГЛ_ВНИЗ)
тип с плавающей запятой
Примеры:
>>> sys.float_info sys.float_info (макс. = 1,7976931348623157e+308, макс_эксп = 1024, max_10_exp=308, мин=2,2250738585072014e-308, мин_эксп = -1021, min_10_exp=-307, копать=15, мант_коп = 53, эпсилон=2,220446049250313e-16, основание = 2, раунды=1) >>> sys.float_repr_style 'короткий' >>> (1.2).as_integer_ratio() (5404319552844595, 4503599627370496)
Форматирование как шестнадцатеричное (основание 16):
>>> (1.1).hex() '0x1.199999999999ap+0' >>> float.fromhex('0x1.199999999999ap+0') 1.1
Округление:
- float.__trunc__(): Округление до нуля (ROUND_DOWN)
- float.__round__(): Округлить до ближайшего, а ничьи — до ближайшего четного целого числа (ROUND_HALF_EVEN).
- float.__int__() является псевдонимом для float.__trunc__() (ROUND_DOWN)
Фракция
>>> fractions.Fraction(5, 10) # int / int Фракция (1, 2) >>> Fraction.Fraction(1.2) # число с плавающей запятой Дробь(5404319552844595, 4503599627370496)
C API
Преобразование объекта Python в целое число. Методы типа:
-
__int__()
: слотtype->tp_as_number->nb_int
-
__index__()
: тип слота->tp_as_number->nb_index
-
__trunc__()
(без слота)
PyNumber_Long(obj)
:
- Вызов
obj.__trunc__()
(Округление до нуля, ROUND_DOWN) - или: если тип
obj
— bytes или str, анализировать строку в десятичном виде (с основанием 10) - или: ошибка!
PyNumber_Index(x)
вызывает метод __index__()
: вызывает исключение, если
тип не имеет метода __index__()
или если метод не возвращает точно
тип int (*).
_PyLong_FromNbInt(x)
:
- Вызов
type(x).__int__(x)
: тип результата должен быть именно типом int (*) - или: ошибка! Если
- вызов
type(x).__index__(x)
если определено: тип результата должен быть точно тип int (*) - вызов
type(x).__int__(x)
(вызов_PyLong_FromNbInt()
): тип результата должен быть точно типом int (*) Ошибка - , если это не подкласс int и тип не определен
__index__()
ни__int__()
метод - Новое в Python 3.8
тип (x) == int
( PyLong_CheckExact()
) PyLong_AsLong()
преобразует Python int
в C long
:
- call
_PyLong_FromNbIndexOrNbInt()
90 292 - поднять OverflowError, если результат не помещается в C long
- Python 3.7 и старше вызывают только
__int__()
, а не__index__()
.
PyLong_AsUnsignedLongMask()
преобразует объект Python в беззнаковый C длинный
:
- вызов
_PyLong_FromNbIndexOrNbInt(x)
и затем_PyLong_AsUnsignedLongMask()
на результат Ошибка - , если объект не может быть преобразован в int с помощью
_PyLong_FromNbIndexOrNbInt(x)
- целочисленное переполнение маски
- Python 3.7 и старше вызывают только
__int__()
, а не__index__()
.
(*) Особый случай: __int__()
или __index__()
возвращают подкласс int. Этот
функция устарела, начиная с Python 3.3 (см. коммит 6a44f6ee).
Эта функция может быть удалена из Python 3.9: см. bpo-17576.
PyArg_ParseTuple и Py_BuildValue
Справочная документация: разбор аргументов и построение значений.
PyArg_ParseTuple реализован в
Python/getargs.c
, основная функция:convertsimple()
.Py_BuildValue реализован в
Python/modsupport.c
, основная функция:do_mkvalue()
.Функции ведут себя по-разному, если определено
PY_SSIZE_T_CLEAN
:Для всех вариантов форматов
#
(s#
,y#
и т.д.) тип файла аргумент длины (int илиPy_ssize_t
) управляется определением макросPY_SSIZE_T_CLEAN
до включенияPython.h
.
Форматы PyArg_ParseTuple:
-
"i"
(Cint
):__index__()
или__int__()
; вызовPyLong_AsLong(obj)
, но явно отклоняет float, используяPyFloat_Check(аргумент)
. -
"l"
(Clong
):__index__()
или__int__()
; вызовPyLong_AsLong()
, но явно отклоняет float, используяPyFloat_Check(arg)
-
"n"
(Cssize_t
):__index__()
; вызовPyNumber_Index()
и затемPyLong_AsSsize_t()
. Исключение при переполнении. -
"k"
: вызовитеPyLong_AsUnsignedLongMask()
, если это подкласс int или int, ошибка иначе. Целочисленное переполнение маски .
Примечание. В Python 3.7 и более ранних версиях PyLong_AsLong()
вызывает только __int__()
,
не __index__()
.
Скрипт для обновления этой страницы
number_tower.py:
из __future__ import print_function импортировать номера предупреждения об импорте импортные фракции импортировать десятичный warnings.simplefilter("ошибка", DeprecationWarning) ЗНАЧЕНИЯ = ( ("целое", 123), ("с плавающей запятой", 1,5), («сложный», сложный (0, 1,5)), ("десятичный.Десятичный", десятичный.Десятичный("1.1")), ("дроби.Дробь", дроби.Дробь(1, 7)), ("байты", б"123"), ("ул", "123"), ) ТИПЫ = ( ("целое", целое), ("плавать", плавать), ("сложный", сложный), ("десятичный.Десятичный", десятичный. Десятичный), ("дроби.Дробь", дроби.Дробь), ) для type_descr, num_type в TYPES: принято = [] отклонено = [] для value_descr, значение в VALUES: пытаться: num_type(значение) кроме TypeError: отклонено.append(value_descr) еще: принято .append (value_descr) если принято: print("``%s(obj)`` accept:" % type_descr) Распечатать() для имени принято: print("* ``%s``" % имя) Распечатать() если отклонено: print("``%s(obj)`` отклонить:" % type_descr) Распечатать() для имени в отклоненном: print("* ``%s``" % имя) Распечатать() Распечатать() для имя_башни, тип_башни в ( ("Число", цифры.Число), ("Комплекс", номера.Комплекс), ("Настоящий", цифры.Настоящий), («Рациональное», числа.Рациональное), ("Интеграл", числа.Интеграл), ): подклассы = [] для type_descr, num_type в TYPES: если issubclass (num_type, tower_type): подклассы.