5

何が問題なのv:=v shl bですか? mask = 2 n -1 のように計算しようとして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 と同じ型です。たとえば、N に値 01101 (10 進数の 13) が格納されている場合、N shl 1 は 11010 (10 進数の 26) を返します。y の値は、x の型のサイズを法として解釈されることに注意してください。たとえば、 x が整数の場合、整数は 32 ビットで 40 mod 32 は 8 であるため、 x shl 40 は x shl 8 と解釈されます。

したがって、64 ビット値の 1 shl 64 は、1 である 1 shl 0 として解釈されます。

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 になることに注意してください。

したがって、バグは 32 ビット コンパイラにのみ存在します。

として報告されましQC112261 SHL operations by constant failsた。


y 値 >= 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 に答える