Как понимать соглашения о знаке
Оба соглашения дают одинаковый результат, когда оба числа положительны, но расходятся, как только появляется отрицательное значение, — как показано ниже.
| a | b | Результат floored (знак b) | Результат truncated (знак a) |
|---|---|---|---|
| 13 | 5 | 3 | 3 (совпадает — оба положительны) |
| −13 | 5 | 2 | −3 |
| 13 | −5 | −2 | 3 |
| −13 | −5 | −3 | −3 (совпадает — оба отрицательны) |
- Floored-остаток (используется здесь как основной результат) — соглашение, наиболее распространённое в чистой математике и теории чисел; оно же соответствует встроенному оператору % в Python.
- Truncated-остаток (показан как дополнительный результат) соответствует встроенному оператору % в JavaScript, C, C++, Java и большинстве языков семейства C, где знак остатка следует за знаком делимого.
- Взятие остатка по нулю не определено и этим калькулятором не вычисляется: делитель должен быть отличен от нуля.
Что такое операция взятия остатка?
Операция взятия остатка, записываемая как a mod b (или a % b), возвращает остаток от деления a на b. Например, 13 mod 5 = 3, поскольку 13 = 2 × 5 + 3: при делении 13 на 5 получается частное 2 и остаток 3. Остаток от деления лежит в основе теории чисел (модульная, или «часовая», арифметика), информатики (хеширование, циклическая индексация, контрольные суммы) и повседневных рассуждений об остатках и циклах — например, о днях недели или часах на циферблате.
Существуют два широко используемых математических соглашения о том, какой знак имеет результат, когда в вычислении участвуют отрицательные числа: floored-остаток, знак которого всегда совпадает со знаком делителя b, и truncated-остаток, знак которого всегда совпадает со знаком делимого a. Оба определения «остатка» математически корректны и в точности совпадают, когда a и b положительны; расхождение возникает только при наличии отрицательного значения.
Выбор соглашения важен на практике, потому что языки программирования реализуют разные значения по умолчанию: оператор % в Python использует floored-остаток, тогда как JavaScript, C, C++, Java и большинство языков семейства C используют truncated-остаток (со знаком делимого). Этот калькулятор явно выводит оба результата, поэтому нужное соглашение можно прочитать напрямую.
Как пользоваться этим калькулятором остатка
- Введите делимое (a) — число, которое делят.
- Введите делитель (b) — число, на которое делят. Делитель не может быть равен 0: деление (а значит, и взятие остатка) на ноль не определено.
- Прочитайте результат по соглашению floored (знак всегда совпадает со знаком делителя) — это математическое соглашение, наиболее распространённое в теории чисел.
- Сравните его с результатом по соглашению truncated (знак всегда совпадает со знаком делимого), если нужно воспроизвести поведение встроенного оператора % конкретного языка программирования, и посмотрите частное и полное уравнение деления для разбора вычисления.
Формулы floored- и truncated-остатка
Floored-остаток определяет частное как q = ⌊a ÷ b⌋ (округление вниз, к минус бесконечности), а затем r = a − b×q. Это гарантирует, что остаток r всегда имеет тот же знак, что и делитель b (либо равен 0), и удовлетворяет условию 0 ≤ r < |b| при b > 0. Разбор примера: 13 mod 5: q = ⌊13/5⌋ = 2, r = 13 − 5×2 = 3.
Разбор примера с отрицательным делимым: −13 mod 5 (floored): q = ⌊−13/5⌋ = ⌊−2,6⌋ = −3, r = −13 − 5×(−3) = −13 + 15 = 2. Обратите внимание: результат положителен (как и положительный делитель) и отличается от truncated-результата ниже.
Truncated-остаток определяет частное округлением к нулю, а не к минус бесконечности, а остаток вычисляет по той же формуле; это гарантирует, что знак остатка всегда совпадает со знаком делимого a (либо остаток равен 0). Разбор примера: −13 mod 5 (truncated, то есть результат % в JavaScript/C/Java): частное округляет −2,6 к нулю до −2, поэтому r = −13 − 5×(−2) = −13 + 10 = −3 — отрицательное значение, совпадающее по знаку с отрицательным делимым, в отличие от floored-результата +2 при тех же входных данных.
Частые ошибки
- Считать, что все языки программирования вычисляют a mod b одинаково для отрицательных чисел: JavaScript, C, C++ и Java используют truncated-остаток, а Python и многие учебники математики — floored-остаток, и результаты различаются всякий раз, когда a отрицательно.
- Забывать, что floored-результат всегда наследует знак делителя, а не делимого, — это противоположно тому, что даёт соглашение truncated (стиль JavaScript).
- Пытаться вычислить a mod 0: операция взятия остатка, как и деление, не определена при нулевом делителе.
- Вводить нецелые значения и ожидать модульной арифметики в целочисленном смысле: калькулятор принимает вещественные числа и применяет ту же логику округления вниз или к нулю, но многие классические свойства модульной арифметики (например, «часовая» арифметика) определены именно для целых чисел.
Часто задаваемые вопросы
Чем floored-остаток отличается от truncated-остатка?
Floored-остаток округляет частное к минус бесконечности, поэтому знак остатка всегда совпадает со знаком делителя. Truncated-остаток округляет частное к нулю, поэтому знак остатка всегда совпадает со знаком делимого. При двух положительных числах они совпадают, но расходятся, если хотя бы одно из чисел отрицательно: например, −13 mod 5 равно 2 по соглашению floored и −3 по соглашению truncated.
Почему −13 mod 5 даёт разные ответы в разных калькуляторах?
Всё зависит от используемого соглашения о знаке. Floored-остаток даёт 2 (знак совпадает со знаком положительного делителя, и выполняется 0 ≤ r < 5). Truncated-остаток даёт −3 (знак совпадает со знаком отрицательного делимого). Оператор % в Python возвращает 2 (floored); операторы % в JavaScript, C и Java возвращают −3 (truncated). Ни один из вариантов не «правильнее»: это два разных, одинаково корректных математических определения.
Как вычислить a mod b вручную?
Разделите a на b, чтобы получить частное, округлите его по выбранному соглашению (вниз для floored, к нулю для truncated), затем вычтите из a произведение b на округлённое частное: остаток = a − b × частное. Для 13 mod 5: 13 ÷ 5 = 2,6, что в обоих случаях округляется до частного 2, поэтому остаток = 13 − 5×2 = 3.
Что означает mod в модульной и «часовой» арифметике?
Модульная арифметика рассматривает числа так, будто они «заворачиваются» по достижении модуля. Классический пример — 12-часовой циферблат, где время считается mod 12 (или mod 24 для 24-часового формата). Например, 15 часов в 24-часовой записи соответствуют 15 mod 12 = 3 на 12-часовом циферблате. Взятие остатка — это и есть операция, которая даёт такой «завёрнутый» остаток.
Можно ли брать остаток по отрицательному делителю?
Да. По соглашению floored результат a mod b (при отрицательном b) имеет тот же знак, что и b: например, 13 mod −5 = −2, поскольку 13 = (−3)×(−5) + (−2). По соглашению truncated остаток вместо этого наследует знак делимого: 13 mod −5 = 3, поскольку частное округляется к нулю до −2, и тогда 13 − (−5)×(−2) = 13 − 10 = 3.
Источники
- Rosen KH. Elementary Number Theory and Its Applications. 6th ed. Pearson, 2010. (Division algorithm and modular arithmetic.)
- Leijen D. Division and Modulus for Computer Scientists. Utrecht University Technical Report UU-CS-2001-20, 2001. (Formal comparison of flooring, truncating and Euclidean division conventions.)
- ECMA International. ECMA-262: ECMAScript Language Specification — the remainder operator (%). ecma-international.org.