Почти наверняка есть более элегантный способ сделать это, но этого достаточно, чтобы вы начали.
Обычно деление таким способом выполняется путем умножения на обратное значение, то есть сначала умножение, а затем вправоshifting.
(Примечание: помните, что умножение может быть выполнено сдвигами и сложениями (например, n * 3 = (n*2) + (n*1) = (n << 1) + (n) )
, но я просто собираюсь использовать умножение здесь. Ваш вопрос сказал «сдвигает и добавляет», и я оправдываюмое сокращенное использование умножения)
В примерах ниже я пытаюсь объяснить концепции на примере. В вашем конкретном случае вы захотите рассмотреть такие вопросы, как
знак (я использую целые числа без знака ниже)
переполнение (ниже я использую 32-битные длинные без знака для хранения промежуточных значений, но если вы напоменьше, остерегайтесь, отрегулируйте соответственно
округление (например, должно ли 9/5 возвращать 1 или 2? В C это 1, но, возможно, вы хотите 2, потому что это ближе к правильному ответу?)
Кв той степени, в которой вы можете (доступные биты), делайте все свои умножения до деления (сводя к минимуму ошибки усечения).Опять же, помните о переполнении.
Как я уже сказал, прочитайте ниже, чтобы понять концепции, а затем адаптировать к вашим потребностям.
Деление на 192 такое же, какумножение на 1/192, что равно делению на (64 * 3).Не существует точного (конечного) двоичного представления 1/3, поэтому мы приближаем его к 0x5555 / (1 << 16). </p>
Чтобы разделить на 192, мы делим на 64, а затем делим на3. Чтобы разделить на 3, мы умножаем на 0x5555 и смещаем вправо на 16 (или умножаем на 0x55 и >> 8, или ...)
// 8000/192 =
// ((8000/64)/3) =
// ((8000 >> 6) / 3) =
// (((8000 >> 6) * 0x5555) >> 16)
// (((8000 * 0x5555) >> 22
Обратите внимание, что круглые скобки являются преднамеренными.Вы не хотите вычислить (8000 * (0x5555/(1 << 16))
, потому что 2-й член равен 0, а произведение равно 0. Не хорошо.
Таким образом, 1-строчная строка в коде будет выглядеть примерно так:
printf("Answer: %lu\n", ((8000UL * 0x5555UL) >> 22));
Это даст 41, то есть то, что "C" выдаст для 8000/192
, даже если 42 равно ".ближе».Проверяя LSB, вы можете округлить, если хотите.
Можно написать трактат на эту тему, но, к счастью, кто-то, намного умнее меня, уже имеет .