2017-02-09 26 views
1

У меня есть метод манипуляции бит, который умножает число на пять восьмых, и если есть раунды остатков в направлении 0. Метод работает, и я понимаю почти все из этого. Однако, когда я его просматривал, я понял, что не уверен, что 7 (00000111) учитывает ошибку округления, в которой она будет округлять к более отрицательному числу вместо 0, и мне нужно понять, почему эта линия работает. Насколько я могу судить, переключение multiplyByFive на 31 бит вправо будет просто проверять знак переменной и выводить все, если отрицательный, поэтому, если он равен 7, либо будет давать все нули, если положительный, или y в двоичном, если отрицательный. Если мое понимание правильное, почему добавление этого значения в multiplyFiveEighths и деление суммы на 8 вокруг отрицательного числа вниз, без ошибок.Бит Манипуляция - Понимание округления к нулевому смещению при умножении отрицательного на фракцию

int multFiveEights(int x) { 

разбить его на умножение на 5 и последующее деление на 8 сдвиге это два влево умножает его на четыре, плюс й делает его на 5

int multiplyByFive = (x << 2) + x; 

если результат является отрицательным, и 2^31 = 7, прежде чем сдвиг вправо

int addNumber = 7 & (multiplyByFive >> 31); 

11111111 (если вы сдвиг вправо на 31, когда отрицательный вы получаете все 1s)

вернет все 0s, если положительные и 1 в LSB, если отрицательный

добавление 7 к multiplyByFive счета за ошибки

если его отрицательный, он будет пытаться округлить, который идет в сторону более отрицательного числа, так Андинг его с 7 счетов для этой ошибки/тесты для остатка

int fiveEigths = (multiplyByFive + addNumber) >> 3; 
return fiveEigths; 
+0

Если 'x' положительный, то вы понимаете, почему' x/8' округляется вниз, но '(x + 7)/8' округляется? – immibis

ответ

1

addNumber будет 7, если multiplyByFive отрицательный и 0, если он положительный (предположим, вы понимаете эту часть).

Итак, логика состоит в том, чтобы добавить 7 к multiplyByFive перед тем, как сдвинуть вправо на 3, но только когда это отрицательно.

Чтобы понять, почему это работает, рассмотрите разницу между округлением и округлением в терминах нижних 3 бит.

Когда нижние 3 бита равны нулю, округление и округление не приведет к какой-либо разнице, поскольку округление не должно происходить из-за того, что число кратно 8 и поэтому делится на 8 (что является правильным сдвиг на 3 делает) дает целочисленный результат.

Если нижние 3 бита - это что-то еще, то итоговый результат округления будет меньше, чем если бы вы округлили.

Добавив 7, вы увеличите конечный результат на 1, путем умножения на 4-й бит в каждом случае, за исключением случаев, когда нижние 3 бита равны нулю. Если все они равны 0, добавление 7 будет устанавливать нижние 3 бита в 1, но не повлияет на четвертое, оставив сдвинутый результат неизменным.

1

(multiplyByFive + 0) >> 3 делится на 8 (всегда округлять вниз), и
(multiplyByFive + 7) >> 3 делит на 8 (всегда округлять вверх).

Ваш код всегда округляется к нулю, проверяя, в каком направлении находится нуль, а затем округляется в этом направлении. Если число для деления отрицательно, то оно добавляет 7, поэтому округляется (что равно нулю). Если он положительный, то он добавляет 0, поэтому округляется (что также равно нулю).