在C位中,乘以3除以16

时间:2014-02-27 18:43:50

标签: c binary bit-manipulation bit puzzle

我的一个伙伴有这些谜题,这是一个躲避我的人。这是问题,给你一个数字,你想要返回该数字乘以3并除以16舍入为0.应该很容易。抓到了吗?你只能使用! 〜& ^ | +<< >>运营商和他们只是12的组合。

int mult(int x){
    //some code here...
return y;
}

我的尝试是:

    int hold = x + x + x;
    int hold1 = 8;
    hold1 = hold1 & hold;
    hold1 = hold1 >> 3;
    hold = hold >> 4;
    hold = hold + hold1;
    return hold;

但这似乎不起作用。我想我有丢失的问题,但我似乎无法想出一种拯救它们的方法。另一种观点是好的。只是要添加,你也可以只使用int类型的变量而不使用循环,如果可以使用语句或函数调用。

现在我有号码0xfffffff。它应该返回0x2ffffff,但它返回0x3000000。

5 个答案:

答案 0 :(得分:3)

对于这个问题,你需要担心分裂前的丢失位(显然)。 基本上,如果它是负数,那么你想在乘以3后加15.一个简单的if语句(使用你的运算符)就足够了。

我不打算给你代码,但一步一步看起来像,

x = x*3

获取标志并将其存储在变量blarg中。

有另一个变量hold x + 15;

设置一个if语句,如果x为负数,则使用添加的15,如果不是,则使用常规数字(我们在上面执行的次数为3次)。

然后除以16你已经告诉你知道该怎么做。祝你好运!

答案 1 :(得分:2)

这似乎有效(只要不发生溢出):

((num<<2)+~num+1)>>4

试试这个JavaScript代码,在控制台中运行:

for (var num = -128; num <= 128; ++num) {
  var a = Math.floor(num * 3 / 16);
  var b = ((num<<2)+~num+1)>>4;
  console.log(
    "Input:", num,
    "Regular math:", a,
    "Bit math:", b,
    "Equal: ", a===b
  );
}

答案 2 :(得分:1)

你可以做的是首先除以4然后再加3次然后再加4。

3*x/16=(x/4+x/4+x/4)/4

有了这个逻辑,程序就可以

main()
{
   int x=0xefffffff;
   int y;
   printf("%x",x);
   y=x&(0x80000000);
   y=y>>31;
   x=(y&(~x+1))+(~y&(x));
   x=x>>2;
   x=x&(0x3fffffff);
   x=x+x+x;
   x=x>>2;
   x=x&(0x3fffffff);
    x=(y&(~x+1))+(~y&(x));
   printf("\n%x %d",x,x);
}

AND与0x3fffffff使msb为零。它甚至可以将数字转换为正数。 这使用2的负数补码。使用直接分割方法,负数的位精度会有所损失。所以使用这个工作来转换-ve到+ ve数然后执行除法运算。

答案 3 :(得分:1)

数学

将正整数n除以16时,得到正整数商k和余数c < 16

    (n/16) = k + (c/16).

(或者只是应用欧几里得算法。)问题要求乘以3/16,所以乘以3

    (n/16) * 3 = 3k + (c/16) * 3.

数字k是一个整数,因此部分3k仍然是整数。但是,int算术会向下舍入,因此如果先划分,则第二项可能会失去精度。自c < 16起,您可以安全地乘以而不会溢出(假设为sizeof(int) >= 7)。所以算法设计可以

    (3n/16) = 3k + (3c/16).

设计

  • 整数k只是n/16向下舍入为0.因此,k可以通过应用单个AND操作找到。另外两项操作将提供3k。操作次数:3。
  • 还可以使用c操作(缺少的位)找到余数AND。乘以3再使用两个操作。轮班完成了分工。操作次数:4。
  • 将它们组合在一起为您提供最终答案。

总操作次数:8。

否定

上述算法使用移位操作。它可能不适用于否定。但是,假设两个补码,n的符号存储在符号位中。可以通过应用算法将其删除并重新应用于答案。

  • 要查找并存储n的符号,只需一个AND即可。
  • 要删除此符号,可以使用OR
  • 应用上述算法。
  • 要恢复符号位,请使用存储的符号位对算法输出执行最后OR操作。

这使最终的操作次数达到11次。

答案 4 :(得分:1)

请注意,C99标准在6.5.7节中指出,有符号负整数的右移调用实现定义的行为。根据{{​​1}}由32位组成并且有符号整数映射到算术移位指令的规定,以下代码适用于所有int输入。一个完全可移植的解决方案也可以满足问题中提出的要求,但我现在想不到一个。

我的基本想法是将数字分成高位和低位以防止中间溢出。首先将高位除以16(这是精确的操作),然后乘以3。首先将低位乘以3,然后除以16.由于算术右移向负无穷大而不是像整数除法那样向零舍入,因此需要对负数的右移应用校正。对于N的右移,如果要移位的数字为负,则需要在移位之前加上2 N -1。

int