Алгоритм
April 14, 2020

Проверка делимости на 3

Недавно ко мне обратился мой бывший ученик - он теперь студент МГУ. Они на первом курсе изучают предмет связанный с низкоуровневым программированием (ассемблер, nasm). Вопрос у него возник по идеи алгоритма для реализации следующего задания: написать программу проверки делимости на 3 без использования операции деления.

Наивная реализация: используем цикл, вычитаем из числа 3, пока оно больше либо равно 3, затем проверяем если число равно 0 - значит оно делится на 3, иначе нет. Проблема в том, что сложность такого решения O(n) и для больших значений n это решение будет работать слишком долго.

Сложить все цифры в десятичной системе не получается, так как для того, чтобы получить цифру в десятичной системе нужно выполнить деление на 10. Выход - использовать двоичную систему счисления и признак делимости на 11.

Число представленное в двоичной системе счисления делится на 3 тогда и только тогда, когда сумма его цифр стоящих на четных местах отличается от суммы цифр, стоящих на нечетных местах, на число, делящееся на 3

Сложение чисел на четных и нечетных позициях в двоичном представлении числа можно реализовать, например, с использованием операции поразрядной конъюнкции и двоичного сдвига вправо. Проверку делимости разницы - осуществить в соответствии с алгоритмом, использующим цикл и условие - описанным выше.

Реализация на C++

bool divisibility3(int n)
{
  int s[2] = {}, k = 0;
  while (n > 0)
  {
    s[k] += (n & 1);
    k = 1 - k;
    n = n >> 1;
  }
  int d = s[0] - s[1];
  if (d < 0) d = s[1] - s[0];
  while(d > 2) d -= 3;
  return (d == 0);
}