Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange SHL operation in Delphi XE

What's wrong with v:=v shl b? I'm trying to calculate mask = 2n-1 like mask:=1 shl n-1, but fails for integer variable 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.

Output:

0
1
0

I suspected v to be zero too.

Solved like 2 shl (n-1)-1. In this case compiler perform machine shl (not __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;

... but, I'm not happy.

like image 403
Srba Avatar asked Jan 29 '13 06:01

Srba


1 Answers

From the documentation :

The operations x shl y and x shr y shift the value of x to the left or right by y bits, which (if x is an unsigned integer) is equivalent to multiplying or dividing x by 2^y; the result is of the same type as x. For example, if N stores the value 01101 (decimal 13), then N shl 1 returns 11010 (decimal 26). Note that the value of y is interpreted modulo the size of the type of x. Thus for example, if x is an integer, x shl 40 is interpreted as x shl 8 because an integer is 32 bits and 40 mod 32 is 8.

So 1 shl 64 on a 64 bit value is interpreted as 1 shl 0 which is 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;

So it seems that there is a compiler bug for 64 bit values when y is a constant.

Note in 64 bit mode, 1 shl 64 results in 1.

So the bug is only in the 32 bit compiler.

Reported as QC112261 SHL operations by constant fails.


If the wanted result of your shift operation was 0 for a y value >= 64, then this function can be used:

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; 

Update

This compiler bug is resolved in version XE4.

like image 117
LU RD Avatar answered Sep 23 '22 08:09

LU RD