CeilLog2函数中的变量BitMask的实际作用是什么?

时间:2018-09-19 14:42:29

标签: c++

这是函数的定义:

inline uint32_t CountLeadingZeros(uint32_t Val)
{
    // Use BSR to return the log2 of the integer
    unsigned long Log2;
    if (_BitScanReverse(&Log2, Val) != 0)
    {
        return 31 - Log2;
    }
    return 32;
}

inline uint32_t CeilLog2(uint32_t Val)
{
    int BitMask = ((int)(CountLeadingZeros(Val) << 26)) >> 31;
    return (32 - CountLeadingZeros(Val - 1)) & (~BitMask);
}

这是我的假设:

函数CountLeadingZeros返回值的范围是[0,32]。当输入Val等于0时,CountLeadingZeros(Val)<< 26应该为1000,0000,....,0000,0000。

因为运算符>>的左侧是带符号的数字,所以>> 32的结果将是1111,1111,....,1111,1111。当Val不等于0时,BitMask始终为0000,0000,....,0000,0000。

所以我想变量BitMask的作用是在输入Val为零时让函数返回0。

但是问题是,当我向该函数传递-1时,它将强制转换为4294967295,导致输出变为32。

我的假设正确吗?

我已经在github上的RayTracing渲染器中多次看到此实现。

BitMask在这里的实际作用是什么?困惑:(

1 个答案:

答案 0 :(得分:1)

  

由于运算符>>的左侧是带符号的数字,所以>> 32的结果将是1111,1111,....,1111,1111。当Val不等于0时,BitMask将始终为0000,0000,....,0000,0000

您的分析是绝对正确的:BitMask要么全为Val,要么为零。否则全为零。您可以使用简单的条件消除BitMask

return Val ? (32 - CountLeadingZeros(Val - 1)) : 0;

这不会创建新分支,因为条件替换了if的{​​{1}}。

  

但是问题是,当我向该函数传递-1时,它将强制转换为4294967295,导致输出变为32。

该函数采用无符号数字,因此您应该传递0xFFFFFFFF,而不是-1(负数的表示是实现定义的)。在这种情况下,返回值应为32,即该值的log 2 上限的正确值。