我有一个变量vBit,它是一个无符号的int64。我知道确实有一个位设置,我需要弄清楚它是哪一个。目前我这样做(在Delphi中):
vPos := -1;
repeat
vBit := vBit shr 1;
inc(vPos);
until vBit = 0;
有更快的方法吗?所有位位置都是相同的,因此平均而言算法需要迭代32次。我正在寻找与ands和xors以及诸如此类的优雅技巧。
答案 0 :(得分:8)
查找第一个位集与计数零位相同,因此this hack might help。顺便说一下,这是一个非常有用的书签页面。
答案 1 :(得分:3)
您可以使用$ FFFFFFFF00000000进行操作,如果非零则添加32 接下来你和$ FFFF0000FFFF0000如果非零,加16等等。 最后你有答案,而且速度非常快:
Result := Ord( ( Val and $FFFFFFFF00000000 ) <> 0 ) * 32 +
Ord( ( Val and $FFFF0000FFFF0000 ) <> 0 ) * 16 +
Ord( ( Val and $FF00FF00FF00FF00 ) <> 0 ) * 8 +
Ord( ( Val and $F0F0F0F0F0F0F0F0 ) <> 0 ) * 4 +
Ord( ( Val and $CCCCCCCCCCCCCCCC ) <> 0 ) * 2 +
Ord( ( Val and $AAAAAAAAAAAAAAAA ) <> 0 );
仅当设置了一个位时才有效!
注意:我没有测试上面显示的例程。
答案 2 :(得分:2)
如果您想快速找到最重要的UInt64位,可以使用以下代码:
function SeniorBit(Lo, Hi: LongWord): Integer;
asm
OR EDX,EDX
JZ @@Lo
MOV EAX,EDX
MOV EDX,32
@@Lo:
OR EAX,EAX
JZ @@Done
BSR EAX,EAX
ADD EAX,EDX
INC EAX
@@Done:
end;
输入值分两部分传递(Lo和Hi longwords)。如果输入为0,则结果为0,否则结果为[1..64]
答案 3 :(得分:1)
您可以尝试使用该数字的基数2对数,但我不知道这是否会更快。这个真的会成为你系统中的性能瓶颈吗?
答案 4 :(得分:1)
也许使用hashtree? (不确定它会更快)。
php中的示例:
$arr = array();
for($i = 0; $i < 64; $i++)
$arr[pow($i, 2)] = $i;
// $arr contains { 1:0, 2:1, 4:2, 8:3, 16:4 etc.
$pos = $arr[$x];
答案 5 :(得分:0)
您可以使用bsf
或bsr
汇编程序指令,该指令查找以32位值设置的第一个或最后一位:
function GetLowestSetBit(AValue: Cardinal): Cardinal; register;
asm
BSR EAX, EAX
end;
要搜索无符号的64位值,您将检查其正确的一半:
procedure TForm1.Button1Click(Sender: TObject);
var
i: Int64;
Index: Cardinal;
begin
i := $8000000000000000;
if i and $FFFFFFFF <> 0 then
Index := GetLowestSetBit(i)
else
Index := 32 + GetLowestSetBit(i shr 32);
Caption := IntToStr(Index); // shows 63
end;
答案 6 :(得分:0)
您可以使用二进制搜索中的策略,而不是连续检查所有位。这会破坏代码大小,但会节省一些处理器周期。
实际上离Ritsaert Hornstra不远的地方 答案。
当然,在汇编中重写这个算法。
但这真的值得痛苦吗?