int r2 (int a, int b)
{
return (a + (1<<(b-1))) >>b;
}
int r3 (int a, int b)
{
return (a + (1<<(b-1)) -1 -(a>>31)) >>b;
}
这个问题在接受我的采访时被问到了。 我很容易扩展表达式,但我没有得到第二个问题的答案。
答案 0 :(得分:3)
这两个函数都可以使用舍入进行右移。即它们将值a / pow(2,b)
舍入为最接近的整数。
不同之处在于a / pow(2,b)
的小数部分恰好是一半。在这种情况下,第一个函数将始终向上舍入,而第二个函数将向零舍入。
第一个函数向上舍入,因为(1<<(b-1)) / pow(2,b)
为0.5,所以它基本上返回floor((a+0.5) / pow(2,b))
。
第二个函数向零舍入,因为a>>31
对于正a
为0或对于-1
为a
(假设为32位二进制补码int
s )。对于否定a
,-1 + (a>>31) == 0
,它返回与第一个函数相同的值,即它将向上舍入为零。对于正a
,-1 + (a>>31) == -1
,所以它会在向右移动之前减去一个,这将导致一半的小数值向下舍入。
答案 1 :(得分:1)
看起来这些函数试图提供舍入而不是截断,以便将正数a除以2除以幂b。 如果你为面试官扩展了这些功能,我相信你已经向他解释了2件事的力量。
(希望你没有像我那样对这些功能嗤之以鼻,否则你可能没有得到这份工作。)
我会告诉他,这些功能在他们围绕* .5分区结果的方式上有所不同,为了支持我的陈述我会向他展示3个例子:
a = 13,b = 3:r2 =&gt; 2,r3 =&gt; 2:13/2 ^ 3 = 1.625
a = 12,b = 3:r2 =&gt; 2,r3 =&gt; 1:12/2 ^ 3 = 1.5
a = 11,b = 3:r2 =&gt; 1,r3 =&gt; 1:11/2 ^ 3 = 1.375
(我不会强调如果你能够将这些内容扩展到那些应该已经足够的话,那么就不会在面试中得到那么多。看起来他只是想向你展示他的“疯狂的技巧”。)
答案 2 :(得分:1)
1.他们之间有什么区别?
两者都以2的幂进行除法,并将结果舍入到最近(如果b
在小范围之外,则用UB)。 r2
轮次绑定。 r3
将关系转向0。
2.在函数r3()中完成使用额外操作的优势是什么?
r3
执行类似int
除法的舍入。 int
除法截断为0。
注意:随着64位int
的出现以及使用16位int
的嵌入式处理器的兴起,对31
进行硬编码是有问题的编码。应该使用类似a>>(sizeof(int) *CHAR_BIT - 1)
的内容而不是a>>31
。
对我来说,这是第一件突出的事情。通过了解公司的市场,它提出了一个机会来展示这种狭隘的C观点如何对公司产生负面影响。
超越回答这个问题。考虑问题的适用性。