Как я могу написать функции сравнения для 64-битных целых чисел без знака для версий компилятора без поддержки UInt64?
Как я могу сделать это с Delphi 6? UInt64 не известен в Delphi 6. Он был представлен в более поздних версиях.
var
i, j: Int64;
if UInt64(i) < UInt64(j) then ...
I am thinking of an asm procedure.
function UInt64CompareLT(i, j: Int64): Boolean;
asm
???
end;
function UInt64CompareGT(i, j: Int64): Boolean;
asm
???
end;
3 ответа
Int64Rec
введите от SysUtils
Предназначен для выбора частей 64-битного целого числа.
Если вы используете Delphi, который предшествует этому типу, определите его самостоятельно:
type
Int64Rec = packed record
case Integer of
0: (Lo, Hi: Cardinal);
1: (Cardinals: array [0..1] of Cardinal);
2: (Words: array [0..3] of Word);
3: (Bytes: array [0..7] of Byte);
end;
Более того, вам нужна только одна функция, которая возвращает -1 для менее чем, 1 для более чем и 0 для равных. Что-то вроде этого:
function CompareUInt64(const i, j: Int64): Integer;
begin
if Int64Rec(i).Hi < Int64Rec(j).Hi then
Result := -1
else if Int64Rec(i).Hi > Int64Rec(j).Hi then
Result := 1
else if Int64Rec(i).Lo < Int64Rec(j).Lo then
Result := -1
else if Int64Rec(i).Lo > Int64Rec(j).Lo then
Result := 1
else
Result := 0;
end;
Идея состоит в том, что вы сначала сравниваете младшую часть, и только если она равна, вы затем сравниваете младшую часть.
Это можно упростить с помощью функции сравнения для Cardinal
,
function CompareCardinal(const i, j: Cardinal): Integer;
begin
if i < j then
Result := -1
else if i > j then
Result := 1
else
Result := 0;
end;
function CompareUInt64(const i, j: Int64): Integer;
begin
Result := CompareCardinal(Int64Rec(i).Hi, Int64Rec(j).Hi);
if Result = 0 then
Result := CompareCardinal(Int64Rec(i).Lo, Int64Rec(j).Lo);
end;
Наконец, если вам нужны булевы функции вашего вопроса, они могут быть реализованы поверх этой более общей функции.
Нет необходимости использовать ассемблер (но, конечно, вы можете это сделать): вместо этого вы можете сравнить высокие и низкие части Int64:
function UInt64CompareLT(i, j: Int64): Boolean;
begin
if (LongWord(i shr 32) < LongWord(j shr 32)) then
Result := true
else if (LongWord(i shr 32) > LongWord(j shr 32)) then
Result := false
else if (LongWord(i and $FFFFFFFF) < LongWord(j and $FFFFFFFF)) then
Result := true
else
Result := false;
end;
function UInt64CompareGT(i, j: Int64): Boolean;
begin
if (LongWord(i shr 32) > LongWord(j shr 32)) then
Result := true
else if (LongWord(i shr 32) < LongWord(j shr 32)) then
Result := false
else if (LongWord(i and $FFFFFFFF) > LongWord(j and $FFFFFFFF)) then
Result := true
else
Result := false;
end;
Использование ассемблера возможно, но связывает ваш код с конкретной архитектурой машины.
Вы можете достичь этого в чистом Паскале следующим образом:
type
//Delcare a variant record to have 2 ways to access the same data in memory.
T64Bit = record
case Integer of
0: (I64: Int64;);
1: (Small: Cardinal; Big: Cardinal);
end;
var
I, J: T64Bit;
begin
//You can set the value via normal Int64 assignment as follows:
I.I64 := 1;
J.I64 := 2;
//Then you can compare the "big" and "small" parts on the number using
//unsigned 32-bit comparisons as follows.
if (I.Big < J.Big) or ((I.Big = J.Big) and (I.Small< J.Small)) then
//The logic is as follows...
// If the big part is less than, the the small part doesn't matter
// If the big parts are equal, then the comparison of the small parts determines the result.