如何确定在unsigned int64中设置了哪个位

时间:2010-01-08 11:28:54

标签: delphi bit-manipulation

我有一个变量vBit,它是一个无符号的int64。我知道确实有一个位设置,我需要弄清楚它是哪一个。目前我这样做(在Delphi中):

vPos := -1;
repeat
  vBit := vBit shr 1;
  inc(vPos);
until vBit = 0;

有更快的方法吗?所有位位置都是相同的,因此平均而言算法需要迭代32次。我正在寻找与ands和xors以及诸如此类的优雅技巧。

7 个答案:

答案 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)

您可以使用bsfbsr汇编程序指令,该指令查找以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不远的地方 答案。

当然,在汇编中重写这个算法。

但这真的值得痛苦吗?