Как взять модуль
Перейти к содержимому

Как взять модуль

  • автор:

6 способов найти модуль числа в Python 3

Модуль числа. Это, казалось бы, простая вещь. да, так оно и есть. Тем не менее — всегда интересно поэкспериментировать и по-новому взглянуть на простое.

Сегодня я покажу вам 6 способов найти модуль числа в Python 3. Я не стал добавлять сюда совсем абсурдные вещи, но немного абсурдности здесь все же будет.

Для начала самое очевидное. Проверяем отрицательное число (назовем его x) или положительное, т.е. <0 или нет. В случае отрицательного значения x, его нужно умножить на -1. Можно так:

А можно заменить умножение унарным минусом:

Самое короткое решение в нашей статье — найти максимум между x и -x. Таким образом результат всегда будет положительным:

Здесь мы проверяем строку на наличие в ней минуса. Изначально я хотел использовать метод isdigit(), но потом я понял, что метод не считает точку частью числа, поэтому для float в строке метод возвращает False. Поэтому:

Этот способ использует условную инструкцию из предыдущей функции, но использует срез, чтобы избавиться от минуса. 3 строка выглядит не очень, приходится дважды менять тип данных результата. По-моему — это ухудшенная версия 3 способа:

Тут мы будем использовать факт того, что операция квадратного корня в Python всегда возвращает положительный результат. Эту операцию не обязательно брать из библиотеки Math, можно просто возвести число в с степень 0.5. Итак:

Здесь мы используем операции со строками, как в 4 способе. Отличие в том, что мы не проверяем строку на наличие минуса. Мы убираем уго, есть он в строке или нет. Метод replace() позволяет убрать все повторения одного символа, что для нас избыточно, но с нулем повторений он тоже работает:

Примечание: говоря про положительные значения, правильнее сказать — положительные или нулевые, но я решил не засорять текст такой мелочью.

Подведем итоги, узнаем — что же быстрее работает. О том, как замерить время работы программы, я, возможно, расскажу в одной из следующих статей. Ну а пока что приведу статистические данные.

Я измерил время работы данного куска кода, где i — одна из 6 функций.

И вот что получилось:

Что у нас по итогу? Худший результат показал 4 способ, неудивительно.Самый очевидный способ — первый, на 2 месте. С большим отрывом лидирует 5 вариант, 100000 повторений за 0.79 сек! Математика быстрее логического оператора if и операций со строками.

Я надеюсь, что вам была интересна данная статья, и вы разобрались в теме. Если хотите меня дополнить — пишите в комментариях. Удачи в мире IT!

Модуль числа в Python

Очень часто возникает необходимость вычисления модуля числа в Python. Рассмотрим, что такое модуль числа, какие есть способы его вычисления. Так же отдельно коснемся комплексных чисел.

Модуль числа

Часто в программировании требуется вычислить абсолютное значение числа. Иначе говоря, отбросить знак.

При вычислении модуля возможны 3 ситуации:

  • Когда число больше 0. Если взять его по модулю — не изменится.
  • Модуль нуля так же равен нулю.
  • У отрицательного числа отбрасываем знак. То есть умножаем его на -1.

Но это все справедливо только для действительных чисел. Чему же тогда будет равен модуль комплексных?

Комплексное число состоит из действительной составляющей и мнимой. Геометрически это можно представить как 2 ортогональные оси: действительную и мнимую. Отмечаем на координатных осях требуемую точку. Модулем будет длина отрезка, проведенного из начала координат в эту точку.

Вычисление

Вычислять модуль можно следующими способами:

  • Используя стандартную функцию abs.
  • С помощью функции fabs библиотеки math.
  • При помощи самостоятельно написанной функции.

Все эти функции работают как в Python 2, так и в Python 3.

Для вычисления в Python модуля числа используется функция abs. Результат функции того же типа, которого был аргумент.

Можно так же воспользоваться функцией fabs из библиотеки math. Библиотеку можно подключить с помощью from math import fabs .

Свое решение

Если по каким то причинам нет возможности или желания использовать стандартные функции, то можно написать свое решение.

Например, можно вычислить воспользоваться тернарным оператором.

На основе такого условия сделаем свою функцию.

Модуль комплексного числа

Мы разобрались как происходит вычисление с действительными числами. Теперь посмотрим, как в языке программирования Python можно получить модуль комплексного.

Функцией fabs мы не сможем воспользоваться. Если попытаемся это сделать, то получим ошибку приведения комплексного числа к действительному (TypeError).

А вот с помощью abs преобразование удается.

Или же напишем свою функцию:

Результаты получились одинаковыми. Но нам все равно пришлось подключить библиотеку math для вычисления квадратного корня.

Получение модуля числа без операции сравнения

Как на C/C++ получить абсолютное значение целого числа без операции сравнения?

ассемблерная операция sar это обычный сдвиг вправо. Вот ваш код:

Я лучше ориентируюсь в Java, поэтому чтобы не выглядить глупо код не буду писать на C 🙂 Но с алгоритмической точки зрения это должно выглядеть примерно так:

(Я полагаю, на С/С++ представление знакового целого сделано с помощью дополнительного кода)

  1. Скопировать куда-нибудь первый бит.
  2. Создать новую целую переменную такого же размера.
  3. Скопировать во все биты второго числа значение сохранённого ранее бита.
  4. Применить побитовое «исключающее или» первого числа ко второму (XOR).
  5. Прибавить к получившемуся числу значение сохранённого ранее бита.

Приведу таблицу действий для чисел -5 и 3 которые хранятся в 8 битах.

число1 доп.число1 доп.бит1 число2 доп.число2 доп.бит2

  1. 11111011 00000000 1 00000011 00000000 0
  2. 11111011 00000000 1 00000011 00000000 0
  3. 11111011 11111111 1 00000011 00000000 0
  4. 00000100 11111111 1 00000011 00000000 0
  5. 00000101 11111111 1 00000011 00000000 0

Алгоритм не супер, но он без сравнений 🙂

Nicolas Chabanovsky's user avatar

Первое, что пришло на ум, сразу после прочтения вопроса, — это взять квадратный корень из квадрата числа:

Другой вариант — это, как уже здесь отмечалось, воспользоваться знаниями о представлении числа и дополнительном коде и побитовыми операциями.

Пример для 8-битных чисел

Для int будет сложнее, т.к. нужно будет учитывать кучу особенностей, например, разрядность (int может быть 8, 16, 32, 64-разрядной) и порядок байтов (Little-Endian/Big-Endian).

Nicolas Chabanovsky's user avatar

Алгоритмический трюк, на котором основано вычисление модуля без ветвлений, заключается в свойстве дополнительного кода. Операция xor с числом -1 даёт инвертирование битов числа, а прибавление 1 завершает переход к отрицанию числа. Причем само число -1 получается как знаковый сдвиг вправо исходного числа, если оно было отрицательным. Если же число было положительным, что сдвиг даст 0, поэтому xor и sub ничего не изменят. Подробнее о подобных алгоритмах вычисления модуля и о скорости их работы можно прочитать здесь.

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.7.31.43551

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Функция abs() для получения модуля числа

Встроенная функция abs(x) в Python возвращает абсолютное значение аргумента x, который может быть целым или числом с плавающей точкой, или же объектом, реализующим функцию __abs__() . Для комплексных чисел функция возвращает их величину. Абсолютное значение любого числового значения -x или +x — это всегда соответствующее положительное +x.

Аргумент x целое число, число с плавающей точкой, комплексное число,
объект, реализующий __abs__()
Возвращаемое
значение
|x| возвращает абсолютное значение входящего аргумента

Пример abs() с целым числом

Следующий код демонстрирует, как получить абсолютное значение 42 положительного числа 42.

Нельзя так просто взять и вычислить абсолютное значение

Кажется, задача вычисления абсолютного значения (или модуля) числа совершенно тривиальна. Если число отрицательно, давайте сменим знак. Иначе оставим как есть. На Java это будет выглядеть примерно так:

Вроде бы это слишком просто даже для вопроса на собеседовании на позицию джуна. Есть ли тут подводные камни?

Вспомним, что в стандарте IEEE-754 вообще и в Java в частности есть два нуля: +0.0 и -0.0. Это такие братья-близнецы, их очень легко смешать и перепутать, но вообще-то они разные. Разница проявляется не только в текстовом представлении, но и в результате выполнения некоторых операций. Например, если поделить единицу на +0.0 и -0.0, то мы получим кардинально разные ответы: +Infinity и -Infinity, отличие между которыми уже сложно игнорировать. Однако, например, в операциях сравнения +0.0 и -0.0 неразличимы. Поэтому реализация выше не убирает минус у -0.0. Это может привести к неожиданным результатам. Например:

Казалось бы, обратное к модулю x число не может быть отрицательным, какое бы ни было x . Но в данном случае может. Если у вас есть садистские наклонности, попросите джуна на собеседовании написать метод abs . Когда же он выдаст код вроде того что в начале статьи, можете спросить, выполнится ли при каком-нибудь x условие 1 / abs(x) < 0 . После таких собеседований про вашу компанию будут ходить легенды.

Ну ладно, проблему мы нашли. А как её исправить? Наивно добавить if (value < 0 || value == -0.0) не получится, потому что +0.0 == -0.0 . В итоге мы сделаем ещё хуже: теперь будет выдаваться -0.0 для положительного нуля на входе. Чтобы надёжно отличить отрицательный нуль, есть метод Double.compare :

Это работает. Но метод становится ужасно медленным для такой тривиальной операции. Double.compare устроен не так уж просто, нам потребуется пара дополнительных сравнений для положительного числа, три сравнения для -0.0 и целых четыре сравнения для +0.0. Если посмотреть на реализацию Double.compare , можно понять, что нам нужна только часть связанная с doubleToLongBits . Этот метод реинтерпретирует битовое представление double -числа как битовое представление long -числа (и там, и там восемь байт). А со сравнением целых чисел никаких сюрпризов нет. Поэтому можно упростить так:

Однако, оказывается, doubleToLongBits тоже не совсем тривиален, потому что он канонизирует NaN’ы. Есть много способов закодировать not-a-number в виде double , но только один из них канонический. Эти разные NaN’ы совсем-совсем близнецы, их не отличишь ни сравнением через Double.compare , никакой операцией, ни строковым представлением. Но в памяти компьютера они выглядят по-разному. Чтобы не было сюрпризов, doubleToLongBits приводит любой NaN к каноническому виду, который записывается в long как 0x7ff8000000000000L . Конечно, это лишние проверки, которые нам здесь тоже не нужны.

Что же делать? Оказывается, можно использовать doubleToRawLongBits , который никаких умностей с NaN ‘ами не делает и возвращает всё как есть:

Этот метод JIT-компилятор в идеале может вообще удалить полностью, потому что речь идёт просто про реинтерпретацию набора бит в процессоре, чтобы типы данных сошлись. А сами биты остаются одни и те же и процессору обычно наплевать на типы данных. Хотя говорят, что всё-таки это может привести к пересылке из регистра с плавающей точкой в регистр общего назначения. Но всё равно очень быстро.

Ладно, у нас осталось два ветвления для всех положительных чисел и нулей. Всё равно кажется, что много. Мы знаем, что ветвления — это плохо, если branch predictor не угадает, они могут очень дорого стоить. Можно ли сделать меньше? Оказывается, можно любой нуль превратить в положительный, если вычесть его из 0.0 :

Таким образом, можно написать:

Зачем так сложно, спросите вы. Ведь можно просто вернуть 0.0 в первом условии. Кроме того, у нас всё равно два сравнения. Однако можно заметить, что для обычных отрицательных чисел 0.0 — value и просто -value дают одинаковый результат. Поэтому первые две ветки легко схлопнуть в одну:

Отлично, у нас теперь всегда одна ветка. Победа? Но как насчёт сделать всегда ноль веток? Возможно ли это?

Если посмотреть на представление числа double в стандарте IEEE-754, можно заметить, что знак — это просто старший бит. Соответственно, нам нужно просто безусловно сбросить этот старший бит. Остальная часть числа при выполнении этой операции не меняется. В этом плане дробные числа даже проще целых, где отрицательные превращаются в положительные через двоичное дополнение. Сбросить старший бит можно через операцию & с правильной маской. Но для этого надо интерпретировать дробное число как целое (и мы уже знаем как это сделать), а потом интерпретировать назад (для этого есть longBitsToDouble , и он тоже практически бесплатный):

Этот способ действительно не содержит ветвлений, и профилирование показывает, что пропускная способность метода при определённых условиях увеличивается процентов на 10%. Предыдущая реализация с одним ветвлением была в стандартной библиотеке Java с незапамятных времён, а вот в грядущей Java 18 уже закоммитили улучшенную версию.

В ряде случаев, впрочем, эти улучшения ничего не значат, потому что JIT-компилятор может использовать соответствующую ассемблерную инструкцию при её наличии и полностью проигнорировать Java-код. Например, на платформе ARM используется инструкция VABS. Так что пользы тут мало. Но всё равно интересная статья получилась!

Как взять число по модулю

Как взять число по модулю

Программно реализовать вычисление модуля можно с использованием условного оператора ветвления if/then — эта конструкция существует практически в любом языке программирования. Например, чтобы значение, содержащееся в переменной с названием $someNum, заменить его модулем на языке php код строки должен выглядеть так:

if($someNum Pascal эту же операцию можно записать так:

Это очень простая и часто используемая математическая операция, поэтому во всех языках программирования есть встроенная функция, которая позволяет обойтись без условного оператора. Как и в Excel, в большинстве программных языков этой функции присвоено название abs, но есть и исключения — в Си она названа fabs. Синтаксис имеет больше различий и подчиняется правилам конкретного языка. Например, описанный выше пример на языке php можно заменить таким применением функции:

Это очень простая и часто используемая математическая операция, поэтому во всех языках программирования есть встроенная функция, которая позволяет обойтись без условного оператора. Как и в Excel, в большинстве программных языков этой функции присвоено название abs, но есть и исключения — в Си она названа fabs. Синтаксис имеет больше различий и подчиняется правилам конкретного языка. Например, описанный выше пример на языке php можно заменить таким применением функции:

Функция abs() для получения модуля числа

Встроенная функция abs(x) в Python возвращает абсолютное значение аргумента x, который может быть целым или числом с плавающей точкой, или же объектом, реализующим функцию __abs__() . Для комплексных чисел функция возвращает их величину. Абсолютное значение любого числового значения -x или +x — это всегда соответствующее положительное +x.

Аргумент x целое число, число с плавающей точкой, комплексное число,
объект, реализующий __abs__()
Возвращаемое
значение
|x| возвращает абсолютное значение входящего аргумента

Пример abs() с целым числом

Следующий код демонстрирует, как получить абсолютное значение 42 положительного числа 42.

6 способов найти модуль числа в Python 3

Модуль числа. Это, казалось бы, простая вещь. да, так оно и есть. Тем не менее — всегда интересно поэкспериментировать и по-новому взглянуть на простое.

Сегодня я покажу вам 6 способов найти модуль числа в Python 3. Я не стал добавлять сюда совсем абсурдные вещи, но немного абсурдности здесь все же будет.

Для начала самое очевидное. Проверяем отрицательное число (назовем его x) или положительное, т.е. <0 или нет. В случае отрицательного значения x, его нужно умножить на -1. Можно так:

А можно заменить умножение унарным минусом:

Самое короткое решение в нашей статье — найти максимум между x и -x. Таким образом результат всегда будет положительным:

Здесь мы проверяем строку на наличие в ней минуса. Изначально я хотел использовать метод isdigit(), но потом я понял, что метод не считает точку частью числа, поэтому для float в строке метод возвращает False. Поэтому:

Этот способ использует условную инструкцию из предыдущей функции, но использует срез, чтобы избавиться от минуса. 3 строка выглядит не очень, приходится дважды менять тип данных результата. По-моему — это ухудшенная версия 3 способа:

Тут мы будем использовать факт того, что операция квадратного корня в Python всегда возвращает положительный результат. Эту операцию не обязательно брать из библиотеки Math, можно просто возвести число в с степень 0.5. Итак:

Здесь мы используем операции со строками, как в 4 способе. Отличие в том, что мы не проверяем строку на наличие минуса. Мы убираем уго, есть он в строке или нет. Метод replace() позволяет убрать все повторения одного символа, что для нас избыточно, но с нулем повторений он тоже работает:

Примечание: говоря про положительные значения, правильнее сказать — положительные или нулевые, но я решил не засорять текст такой мелочью.

Подведем итоги, узнаем — что же быстрее работает. О том, как замерить время работы программы, я, возможно, расскажу в одной из следующих статей. Ну а пока что приведу статистические данные.

Я измерил время работы данного куска кода, где i — одна из 6 функций.

И вот что получилось:

Что у нас по итогу? Худший результат показал 4 способ, неудивительно.Самый очевидный способ — первый, на 2 месте. С большим отрывом лидирует 5 вариант, 100000 повторений за 0.79 сек! Математика быстрее логического оператора if и операций со строками.

Я надеюсь, что вам была интересна данная статья, и вы разобрались в теме. Если хотите меня дополнить — пишите в комментариях. Удачи в мире IT!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *