这是函数的定义:
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在这里的实际作用是什么?困惑:(
答案 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 上限的正确值。