按位乘以5/8观察溢出

时间:2017-02-17 01:56:46

标签: c

我被分配了许多问题,这是我唯一无法弄清楚如何优化的问题。

目标是乘以5/8舍入为0并防止溢出。操作顺序乘以5然后除以8(即11 * 5/8 = 6)。优化的目标是使用12个或更少的运算符。

只有规定! 〜& ^ | +<< >>允许操作和8位整数。

我目前对解决方案的尝试是

int trueFiveEighths (int x){
    int rightOne = x >>1;
    int rightTwo = x >>2;
    int temp = (x &(rightTwo) &1) + (((x ^(rightTwo))|(rightOne)|x)&(x>>31)&1);
    return (x>>3) + (rightOne) + temp;
}

其中有14项运作。我没有办法让任何更多的操作员刮掉,我无法想出另一种方法。

2 个答案:

答案 0 :(得分:7)

你可以除以8:

int const eights = x >> 3;

得到余数:

int const rem = x & 7;

将每个乘以5:

eights += eights << 2;
rem += rem << 2;

并添加任何新的整体:

eights += rem >> 3;

组合:

int const eights = x >> 3;
int const rem = x & 7;

return eights + (eights << 2) + (rem + (rem << 2) >> 3);

总计八个计算的运算符。

要将不能被8整除的负数舍入为零,请利用符号扩展(实现定义,因此不可移植,但可能是预期的解决方案)来获得负数值7和正数值0:

int const negative_mask = x >> 31 & 7;

return eights + (eights << 2) + (rem + (rem << 2) + negative_mask >> 3);

所有在一起:

int const eights = x >> 3;
int const rem = x & 7;

return eights + (eights << 2) + (rem + (rem << 2) + (x >> 31 & 7) >> 3);

11名运营商。

答案 1 :(得分:0)

在这里,我们乘以4,然后将X加到5,然后加1/2 1/2进行舍入。 然后,除以8(第3班)。

return ((x << 2) + (x) + (x >> 1)) >> 3;

如果截断为0,

return ((x << 2) + (x)) >> 3;

这本身不会防止溢出,因为我们首先乘以5。我们可以先下降,但后来我们失去了精确度。将乘法与向下移位混合可以很好地为您提供精确度和溢出保护之间的中间地带。

上面的方法确实具有使用非常少的操作的优点,并且是我在内置乘法器(Gameboy / GBC)的系统上的后台机器中使用的代码