Как реализовать проверку кратности с остатком от деления в JavaScript
Что проверяют
Базовое знание оператора % и, главное, его поведения на неудобных входах: отрицательные числа, ноль, дроби, большие числа. Уточняющий вопрос обычно такой: «Что вернёт -7 % 3 и как проверить нечётность?»
Как отвечать
Сама проверка короткая: n % d === 0. Ценность ответа в том, что вы знаете про оператор:
- это остаток, а не модуль: знак результата совпадает со знаком делимого,
-7 % 3даёт-1, а не2. Для математического модуля пишут((n % d) + d) % d; - отрицательный ноль:
-6 % 3вернёт-0. Строгое-0 === 0истинно, так что проверка кратности работает, ноObject.is(-0, 0)ужеfalse; - деление на ноль: исключения нет,
5 % 0даётNaN, аNaN === 0ложно. Функция молча скажет «не кратно», поэтому ноль лучше проверять явно и решить, бросать лиRangeErrorили возвращатьfalse; - дроби:
0.3 % 0.1даёт0.09999999999999998из-за двоичного представления. Деньги считают в целых копейках, остальные дроби сравнивают с допуском; - большие числа: после
Number.MAX_SAFE_INTEGER, то есть2 ** 53 - 1, точность теряется, и остаток становится неверным. Здесь нуженBigInt:10n % 3n === 1n, а деление на0nуже бросаетRangeError.
Хорошо дополнить ответ проверкой Number.isInteger(n) на входе, если функция рассчитана только на целые.
Где спотыкаются
Проверяют нечётность как n % 2 === 1. Для -3 результат -1, и отрицательное нечётное число считается чётным. Надёжнее n % 2 !== 0.
Путают % с модулем из математики и ждут неотрицательный результат, например при вычислении индекса в кольцевом буфере: (i - 1) % length на нулевом индексе даёт -1.
Не думают о приведении типов. Значение из поля формы приходит строкой, "" % 3 даёт 0, и пустое поле внезапно оказывается кратным трём. Приводите явно через Number() и отсекайте NaN и пустые строки до вычислений.