位操作 - 理解将负数乘以分数时向零偏差舍入

Bit Manipulation- Understanding Rounding Toward Zero Bias When Multiplying A Negative By a Fraction

我有一个位操作方法,将一个数乘以八分之五,如果有余数则向0舍入。该方法有效,我几乎了解所有内容。然而,当我审查它时,我意识到我不确定 anding 7 (00000111) 是如何解释舍入误差的,在舍入误差中它会舍入到一个更负的数而不是 0,我需要理解为什么这条线有效。据我所知,将 multiplyByFive 向右移动 31 位只会检查变量的符号,如果为负则产生所有 1,因此如果为正则将其与 7 相加将产生全零,如果为负则产生二进制 y。如果我的理解是正确的,为什么将其与 multiplyFiveEighths 相加并将总和除以 8 将负数向下舍入,而不会出现错误。

int multFiveEights(int x) {

将其分解为乘以 5 再除以 8 将它向左移动二乘以四,加上 x 使它乘以 5

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

如果结果为负,且右移前2^3 - 1 = 7

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

11111111(如果您在负数时右移 31,则全为 1)

将 return 如果为正则全为 0,如果为负则在 LSB 中为 1

将 7 加到 multiplyByFive 中会导致错误

如果它是负数,它会尝试向下舍入到更负数,所以用 7 来解释这个错误/测试余数

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

(multiplyByFive + 0) >> 3 除以 8(总是向下舍入),
(multiplyByFive + 7) >> 3 除以 8(总是四舍五入)。

您的代码总是通过检查零所在的方向然后朝该方向舍入来向零舍入。如果要除的数是负数,则它会加 7,因此会向上舍入(接近零)。如果为正,则加 0,因此向下舍入(也向零舍入)。

addNumbermultiplyByFive 为负时为 7,在为正时为 0(我假设你理解这部分)。

因此,逻辑是在右移 3 之前将 multiplyByFive 加 7,但仅当它为负数时才如此。

要理解为什么这样做,请考虑在低 3 位方面向下舍入和向上舍入之间的区别。

当低3位为零时,向上舍入和向下舍入不会产生任何差异,因为不需要进行舍入,因为数字是8的倍数所以除以8(这是右移 3 确实)产生一个整数结果。

当低 3 位为其他任何值时,向下舍入的最终结果将比向上舍入时少一位。

通过加 7,最终结果将增加 1,除低 3 位为零外,在每种情况下都通过第 4 位计时。如果全为0,加7会将低3位置1,不影响第4位,移位后的结果不变。