Прошло больше месяца, новых знаний не писал. Итак, здесь я собираюсь написать об операторе по модулю в Python.

Наткнулся на оператор по модулю для отрицательных чисел. Я сталкивался с этим однажды. Итак, здесь я перечисляю, как работает модуль.

Краткое руководство по модулю:

Термин по модулю происходит из раздела математики, называемого модульной арифметикой. Оператор по модулю используется для получения значения в конечных границах. Классический пример — часы. Двенадцатичасовые часы имеют фиксированный набор значений от 1 до 12. Они имеют модуль 12.

Если мы хотим узнать, сколько времени будет через 7 часов после 8 утра, вы можете просто прибавить 7 к 8 и взять по модулю.

8 o'clock + 7 = 15
15 mod 12 = 3

Это означает, что 7 часов после 8:00 — это 15:00.

Теперь вы можете думать, что 15 и 3 эквивалентны в контексте мода 12. Модульная арифметика описывает это отношение как

a ≡ b(mod n)

Поместим это в наш пример:

15 ≡ 3 (mod 12)

читать как 15 конгруэнтно 3 по модулю 12.

Теперь давайте найдем модуль различных типов чисел.

Для положительного дивиденда и положительного делителя:

>>> 15%2
1

Для отрицательного делимого и положительного делителя:

>>> -15%2
1

Мы видим, что как для положительных, так и для отрицательных дивидендов положительный делитель дает нам положительный остаток.

Теперь перейдем к положительному делимому и отрицательному делителю:

>>> 15%-2
-1

Для отрицательного делимого и отрицательного делителя:

>>> -15%-2
-1

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

В Python есть метод divmod, который дает нам и делимое, и остаток. Давайте посмотрим, какие значения мы получаем для вышеуказанных случаев:

>>> divmod(15,2)
(7, 1)
>>> divmod(-15,2)
(-8, 1)
>>> divmod(15,-2)
(-8, -1)
>>> divmod(-15,-2)
(7, -1)

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

Однако это правило не применяется в операторе по модулю чисел с плавающей запятой в зависимости от того, как вы получаете остаток:

>>> math.fmod(-12.0, 5.0)
-2.0
>>> -12.0%5.0
3.0

Если мы получим остаток, используя math.fmod, остаток будет отрицательным, даже если делитель положительный. В то время как, если мы поступим нормально по модулю, мы получим положительный остаток.

Почему это? Это из-за того, как язык получает частное — trucated division или floor divison.

Для усеченного деления, когда отрицательное частное округляется до нуля, используется следующее уравнение:

r = a — (n * trunc(a/n))

где

r = remainder
a = dividend
n = divisor

math.fmod использует это правило truncated division, поэтому мы получаем отрицательный остаток, когда делимое отрицательно, даже если делитель положительный.

Разработаем это уравнение:

r = -12.0 - (-5.0 * trunc(-12.0/5.0))
r = -12.0 - (-5.0 * trunc(-2.4))
r = -12.0 - (5.0 * -2)
r = -12.0 + 10
r = -2

Для деления этажей, где отрицательное частное округляется от нуля, используется следующее уравнение:

r = a - (n * floor(a/n))

где

r = remainder
a = dividend
n = divisor

Простой модуль использует это floor division, поэтому мы получаем положительный остаток, когда делимое отрицательно, а делитель положительный.

r = -12.0 - (5.0 * floor(-12.0/5.0))
r = -12.0 - (5.0 * floor(-2.4))
r = -12.0 - (5.0 * -3)
r = -12.0 +15
r = 3

Вот и все.

В заключение, в Python для целых значений, если делитель положительный, остаток будет положительным, иначе отрицательным. Для отрицательных дивидендов с плавающей запятой это зависит от того, как вы получаете значение по модулю. Если вы используете обычный оператор %, остаточное значение будет положительным из-за использования деления floor. Если вы использовали math.fmod, вы получите отрицательное значение остатка, так как будет использоваться truncated деление.

Надеюсь, это было полезно. Спасибо за чтение. 🪁

Вдохновение:

Вы можете поддержать меня на Патреоне.