Reputation: 552
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?
Upvotes: 1
Views: 1893
Reputation: 58
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.
Upvotes: 0
Reputation: 1
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
Upvotes: -1
Reputation: 613511
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.
Upvotes: 12
Reputation: 28839
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".
Upvotes: 2