3

I'm porting some C# code to Delphi (XE5). The C# code has code like this:

long t = ...
...                
t = (t >> 25) + ...

I translated this to

t: int64;
...
t := (t shr 25) + ...

Now I see that Delphi (sometimes) calculates wrong values for shifting negative t's, e.g.:

-170358640930559629 shr 25
Windows Calculator: -5077083139
C# code: -5077083139

Delphi: 
-170358640930559629 shr 25               = 544678730749 (wrong)

For this example, -1*((-t shr 25)+1) gives the correct value in Delphi.

For other negative values of t a simple typecast to integer seems to give the correct result:

integer(t shr 25)

I am at my limit regarding binary operations and representations, so I would appreciate any help with simply getting the same results in Delphi like in C# and Windows calculator.

  • The problem is explained in this comment: http://stackoverflow.com/questions/5348540/what-is-a-equivalent-of-delphi-shl-in-c#comment6042256_5348558 – Stefan Glienke Feb 21 '14 at 17:49
  • Your `-1*((-Value shr Bits)+1)` fails when `Value = -4` and `Bits = 1`. It returns `-3` instead of `-2`. – JRL Feb 21 '14 at 21:23

2 Answers2

4

Based on the article linked in Filipe's answer (which states the reason to be Delphi carrying out a shr as opposed to others doing a sar), here's my take on this:

function CalculatorRsh(Value: Int64; ShiftBits: Integer): Int64;
begin
  Result := Value shr ShiftBits;
  if (Value and $8000000000000000) > 0 then
    Result := Result or ($FFFFFFFFFFFFFFFF shl (64 - ShiftBits));
end;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • +1. This works great. When ´Value´ is negative, it replaces the leftmost `0` bits put by `shr` with the correct `1` bits. The `and` condition is equivalent to `Value < 0`. – JRL Feb 21 '14 at 21:41
  • @JRL - Thanks! Do you think making the 'negative' test more readable would be good here? After all it involves some bit shifts.. – Sertac Akyuz Feb 21 '14 at 21:47
  • Would the same function for 32-bit integers look like this? function CalculatorRsh(value:integer; ShiftBits : integer): integer; begin Result := Value shr ShiftBits; if (Value and $80000000) > 0 then Result := Result or ($FFFFFFFF shl (32 - ShiftBits)); end; – user3338237 Feb 22 '14 at 16:50
  • @user - Tried it now, it gives a range check error on $FFFFFFFF (if range checking is on), cast it to an integer, or replace with -1. – Sertac Akyuz Feb 23 '14 at 02:30
0

As you can read here, the way C and Delphi treat Shr is different. Not meaning to point fingers, but C's >> isn't really a shr, it's actually a sar. Anyways, the only workaround that I've found is doing your math manually. Here's an example:

function SAR(a, b : int64): int64;
begin
  result := round(a / (1 shl b));
end;

Hope it helps!

Filipe.Fonseca
  • 321
  • 2
  • 14
  • Your SAR function seems to be of by one: SAR(-1841198311509,25) returns -54871, while Windows Calc returns -54872. – user3338237 Feb 21 '14 at 18:47
  • Just changed the function, take a look and see what you think. It's edited at the answer. – Filipe.Fonseca Feb 21 '14 at 19:22
  • 1
    @GJ. - See revision history, and the first comment to the answer. – Sertac Akyuz Feb 21 '14 at 21:21
  • Both `round(a / (1 shl b))` and `a div (1 shl b))` fail when `a = -5` and `b = 1`. Both return `-2` instead of `-3`. – JRL Feb 21 '14 at 21:29
  • 1
    That article is a poor source. C's `>>` is *implementation-defined* for negative operands, so it's unhelpful to compare it with Delphi's shift operator. Better to compare with C#, as the question did. – Rob Kennedy Feb 22 '14 at 06:14