5

有什么问题v:=v shl b?我正在尝试计算mask = 2 n -1 like mask:=1 shl n-1,但对于整数变量 n=64 失败。

program UInt64Test;

{$APPTYPE CONSOLE}

var
  u,v,w:uint64;
const
  a=64;
var
  b:integer=a;
  c:integer=a-1;

begin
  u:=1; v:=1; w:=1;
  u:=u shl a;
  v:=v shl b;
  w:=w shl 1 shl c;
  writeln(u);
  writeln(v);
  writeln(w);
  readln;
end.

输出:

0
1
0

我也怀疑v是零。

解决之类的2 shl (n-1)-1。在这种情况下,编译器执行机器shl(不是__llshl):

function reciprocal(o:uint64;n:byte=64):uint64; // result * o = 1 (mod 2ⁿ)
var
  b,m,t:uint64;
begin
  result:=0;
  t:=2 shl (n-1)-1;
  m:=0; b:=1;
  while b<>0 do begin
    m:=m or b;
    if ((o*result) and m)<>1 then result:=result or b;
    b:=(b shl 1) and t;
  end;
end;

……但是,我不开心。

4

1 回答 1

11

来自documentation

操作 x shl y 和 x shr y 将 x 的值向左或向右移动 y 位,这(如果 x 是无符号整数)相当于将 x 除以 2^y;结果与 x 的类型相同。例如,如果 N 存储值 01101(十进制 13),则 N shl 1 返回 11010(十进制 26)。请注意,y 的值被解释为以 x 类型的大小为模。因此,例如,如果 x 是整数,则 x shl 40 被解释为 x shl 8 因为整数是 32 位而 40 mod 32 是 8

因此 64 位值上的 1 shl 64 被解释为 1 shl 0 即 1。

const
  aa = 32;
var
  x,y,z : Cardinal;
...
x := 1;
y := 32;
z := x shl aa; // Gives z = 1
z := x shl 32; // Gives z = 1
z := x shl y;  // Gives z = 1;

因此,当 y 是常量时,似乎存在 64 位值的编译器错误。

注意在 64 位模式下,1 shl 64 结果为 1。

所以这个bug只存在于32位编译器中。

报告为QC112261 SHL operations by constant fails


如果对于 ay 值 >= 64,移位操作的所需结果为 0,则可以使用此函数:

function ShiftLeft( AValue : UInt64; bits : Integer) : UInt64; inline;
begin
  if (bits > 63) then 
    Result := 0 // Avoid bits being modified modulo 64
  else
    Result := AValue shl bits;
end; 

更新

此编译器错误已在 XE4 版本中得到解决。

于 2013-01-29T07:37:20.017 回答