1
votes

I wrote a small function to convert MB to Bytes, however, there seems to be a bug in int64. According to the documentation, int64 ranges from -9223372036854775808 to 9223372036854775807, but my results differ...a lot:

Const FreeSpace = 67100;

var FreeSpaceConverted :int64;
.
.
.

FreeSpaceConverted := FreeSpace shl 20;

Using a value of 67100 for FreeSpace results in a value of 1639972864 instead of 70359449600. It's obvious that the conversion ran out of space and wrapped around. The actual size of int64 seems to be 70359449600 - 1639972864 = 68719476736 = 2^36 while it should be 2^63-1. An exponent of 36 looks rather strange. Could it be a number twist in the compiler itself??

Also, using the following alternative gives the error "Overflow in conversion or arithmetic operation" even though it shouldn't:

FreeSpaceConverted := FreeSpace * 1024 * 1024;

On the other hand, the following alternative does work:

FreeSpaceConverted := FreeSpace * 1024;
FreeSpaceConverted := FreeSpaceConverted * 1024;

Is this normal behavior and if so, what's the reason for all of this?

4
-1. Code in question does not exhibit described problem. Always copy and paste real code, especially when accusing the compiler of having a bug.Rob Kennedy
I asked whether this could be a bug. I never declared it was, much less "accused" the compiler of anything. Besides, the surrounding code is several thousand lines long and is not related to the function at all. If I had posted the whole source, no one would have read it. If I had posted a random set of functions it wouldn't have helped either and you could still complain about the incompleteness of the source, which as already said has nothing to do with the solution. The only mistake I made was by not declaring FreeSpace as a constant in the example above like I did in my code.Zerobinary99
@Zerobinary99 I can understand where both you and Rob are coming from. When faced with such a situation the best thing to do, in your shoes, is to create the smallest possible program that exhibits the unexplained behaviour. Obviously you can't show the entire code but making a small reproducing example is always a good idea. Many times the act of doing that will lead you to the answer. I myself have spent the last two days doing exactly that at work!David Heffernan
That's exactly what I tried. I just thought I could keep things short by not writing that "const" declaration which coincidentally was the key to the errors I experienced. Well, I'm only like 4 weeks into Delphi, so I'd label that as a beginner's mistake. I can only get better (at programming and asking questions) ;)Zerobinary99

4 Answers

12
votes

All the code you include in the question works fine in Delphi 7.

program Int64Test;

{$APPTYPE CONSOLE}

var
  FreeSpaceConverted, FreeSpace: Int64;

begin
  FreeSpace := 67100;
  FreeSpaceConverted := FreeSpace shl 20;
  Writeln(FreeSpaceConverted);
  FreeSpaceConverted := FreeSpace * 1024 * 1024;
  Writeln(FreeSpaceConverted);
  Readln;
end.

Output

70359449600
70359449600

Your actual code is different from what you have stated in the question. In fact, FreeSpace is declared as a 32 bit type in your code, probably Integer. For example, and I'm having to guess a little here:

program Int64Test;

{$APPTYPE CONSOLE}

var
  FreeSpace: Integer;
  FreeSpaceConverted: Int64;

begin
  FreeSpace := 67100;
  FreeSpaceConverted := FreeSpace shl 20;
  Writeln(FreeSpaceConverted);
  FreeSpaceConverted := FreeSpace * 1024 * 1024;
  Writeln(FreeSpaceConverted);
  Readln;
end.

Output

1639972864
1639972864

If we enable overflow checking then the multiplication code results in an overflow exception, as you report.


Now consider FreeSpace shl 20 when FreeSpace is an integer. The compiler interprets this as a 32 bit integer operation and shifts the more significant bits off the end of the 32 bit register. The fact that you are assigning to a 64 bit integer is not relevant. What matters are the data types in the expression. You can make the code behave the way you want by including a cast to Int64 on the right hand side.

program Int64Test;

{$APPTYPE CONSOLE}

var
  FreeSpace: Integer;
  FreeSpaceConverted: Int64;

begin
  FreeSpace := 67100;
  FreeSpaceConverted := Int64(FreeSpace) shl 20;
  Writeln(FreeSpaceConverted);
  FreeSpaceConverted := Int64(FreeSpace) * 1024 * 1024;
  Writeln(FreeSpaceConverted);
  Readln;
end.

Output

70359449600
70359449600

For a fuller discussion I refer you to Barry Kelly's answer to another question.

2
votes

I don't happen to have D7 on this system but I do have Delphi 2007 and in that, this code:

var
  FreeSpaceConverted, FreeSpace:int64;
begin
  try
     FreeSpace := 67100;
     FreeSpaceConverted := FreeSpace shl 20;
     writeln(FreeSpaceConverted);
     readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

yields "70359449600".

0
votes

I'm using Delphi XE7. I think the problem is with shifting a 32-bit integer into a 64-bit integer. If I use the your code, I get the same thing you do. But if I first typecast FreeSpace to int64, i.e.

Const FreeSpace : int64 = 67100;

I get the correct result.

-1
votes

Okay, so this line doesn't work -> FreeSpaceConverted := FreeSpace shl 20;

Perhaps you should watch this part -> FreeSpace shl 20;

Yes, FreeSpace shl 20, and you may want to look this -> const -> FreeSpace = 67100;

Perhaps D7 considers FreeSpace as Integer 32 constant? If so, you might want to change your code into something like this -> const -> FreeSpace: Int64 = 67100;

You don't need untyped constant here, unless you want to do something like this var A: array [0..FreeSpace] of Integer Other than that you don't need untyped constant.

Further information In Pascal untyped constant is like a text editor replacement. You can use untyped constant where you use number. It doesn't take any memory reference, it's just a TEXT EDITOR REPLACEMENT. You can't make any operation in that Example: const A: Integer = 10; B = 20;

begin Inc(A); // it works Inc(B); // not only it won't work, it also generates compile error end;

Comparison Untyped Constant Typed constant C #define A 20 long a = 20;
Pascal const A = 20; const A: Integer = 20;
Assembly A equ 20 A dd 20 ; double word, integer 32 ; equivalent in assembly