将x> = y转换为1或0而不使用分支或布尔表达式

时间:2017-07-31 10:08:10

标签: c bit-manipulation integer-arithmetic

我需要在没有分支或布尔表达式的情况下实现以下函数:

uint8_t func(uint32_t num, uint8_t shl)
{
    if (num >= (1 << shl))
    {
        return shl;
    }
    else
    {
        return 0;
    }
}

我做的第一步是注意到else部分很简单:

return num / (1 << shl);

当然,在if部分执行此操作不一定会产生预期的结果。

所以我想我需要比num / (1 << shl)更“聪明”的东西。

如果我能提出一个能给我10的表达,那么我就完成了。

是否有某种方法只使用算术/按位运算(即没有分支或布尔表达式)?

谢谢。

4 个答案:

答案 0 :(得分:7)

您可以将条件视为一个布尔表达式,其计算结果为TRUE(1)或FALSE(0),因此您可以使用以下内容:

Excel::load('path to file\stlist.xlsx', function($reader) {

    // reader methods

});

这段代码通常不是一个好主意,但在无分支约束下,它可以胜任。

答案 1 :(得分:4)

如果您想避免使用比较运算符,可以使用减法和位移来探测符号位:

uint8_t func(uint32_t num, uint8_t shl) {
    return shl * (1 - ((num-(1<<shl)) >> (sizeof(num) * CHAR_BIT -1)));
} 

Demo

答案 2 :(得分:3)

假设您的实现arithmetic shift(通常是这种情况)以及二进制补码算法,您可以利用符号位传播:

uint8_t func(uint32_t num, uint8_t shl)
{
    return (-(int32_t)(num >> shl) >> 31) & shl;
}

可能转换为无分支x86汇编代码:

func(unsigned int, unsigned char):
  mov eax, edi
  mov ecx, esi
  shr eax, cl
  neg eax
  sar eax, 31
  and eax, esi
  ret

主要思想是&的左操作数是全部或全部为零,这意味着shl的值保留或归零。

最棘手的部分是-(int32_t)(num >> shl)。它建立在事实的基础上:

  • num / (1 << shl)表达式与num >> shl
  • 基本相同
  • 无符号值的右移总是用零填充左位
  • shl == 0时,结果总是0(即&的左操作数的值是无意义的,因为它会被shl丢弃

答案 3 :(得分:-3)

怎么样?

bool func( int32_t num, int8_t shl)
{
  return (num>=(1<<shl));
}
  • Return 1 if x>=(1<<y)
  • Return 0 if x<(1<<y)