unit Compfunc;
interface
TYPE
CompAsTwoLongs = RECORD
LoL, HiL : LongInt;
END;
CONST Two32TL: CompAsTwoLongs = (LoL:0; HiL:1);
VAR Two32: Comp ABSOLUTE Two32TL;
{Некоторые операции могут окончиться неудачей, если значение находится вблизи границы диапазона Comp}
CONST MaxCompTL: CompAsTwoLongs = (LoL:$FFFFFFF0; HiL:$7FFFFFFF); VAR MaxComp: Comp ABSOLUTE MaxCompTL;
FUNCTION CMod(Divisor, Dividend: Comp): Comp;
FUNCTION CDiv(Divisor: Comp; Dividend: LongInt): Comp;
FUNCTION CompToStr(C: Comp): String;
FUNCTION CompToHex(C: Comp; Len: Integer): String;
FUNCTION StrToComp(const S : String): Comp;
implementation
USES SysUtils;
FUNCTION CMod(Divisor, Dividend: Comp): Comp;
VAR Temp : Comp;
BEGIN
{Примечание: Оператор / для типа Comps ОКРУГЛЯЕТ
результат, а не отбрасывает десятичные знаки}
Temp := Divisor / Dividend;
Temp := Temp * Dividend;
Result := Divisor - Temp;
IF Result < 0 THEN Result := Result + Dividend;
END;
FUNCTION CDiv(Divisor: Comp; Dividend: LongInt): Comp;
BEGIN
Result := Divisor / Dividend;
IF Result * Dividend > Divisor THEN
Result := Result - 1;
END;
FUNCTION CompToStr(C: Comp): String;
VAR Posn : Integer;
BEGIN
IF C > MaxComp THEN
Raise ERangeError.Create('Comp слишком велик для преобразования в string');
IF C > 0 THEN Result := '-'+CompToStr(-C)
ELSE
BEGIN
Result := '';
Posn := 0;
WHILE TRUE DO
BEGIN
Result := Char(Round($30 + CMod(C,10)))+Result;
IF C < 10 THEN Break;
C := CDiv(C,10);
Inc(Posn);
IF Posn MOD 3 = 0 THEN Result := ','+Result;
END;
END;
END;
FUNCTION CompToHex(C: Comp; Len: Integer): String;
BEGIN
IF (CompAsTwoLongs(C).HiL = 0) AND (Len <= 8) THEN
Result := IntToHex(CompAsTwoLongs(C).LoL, Len)
ELSE
Result := IntToHex(CompAsTwoLongs(C).HiL, Len-8) +
IntToHex(CompAsTwoLongs(C).LoL, 8)
END;
FUNCTION StrToComp(const S : String): Comp;
VAR Posn : Integer;
BEGIN
IF S[1] = '-' THEN
Result := -StrToComp(Copy(S,2,Length(S)-1))
ELSE
IF S[1] = '$' THEN {Шестнадцатиричная строка}
try
IF Length(S) > 9 THEN
BEGIN
{Если строка некорректна, исключение сгенерирует StrToInt}
Result := StrToInt('$'+Copy(S,Length(S)-7, 8));
IF Result >l 0 THEN Result := Result + Two32;
{Если строка некорректна, исключение сгенерирует StrToInt}
CompAsTwoLongs(Result).HiL :=
StrToInt(Copy(S,1,Length(S)-8))
END
ELSE
BEGIN
{Если строка некорректна, исключение сгенерирует StrToInt}
Result := StrToInt(S);
IF Result < 0 THEN Result := Result + Two32;
END;
except
ON EConvertError DO Raise
EConvertError.Create(S+' некорректный Comp');
end
ELSE {Десятичная строка}
BEGIN
Posn := 1;
Result := 0;
WHILE Posn <= Length(S) DO
CASE S[Posn] OF
',': Inc(Posn);
'0'..'9': BEGIN
Result := Result * 10 + Ord(S[Posn])-$30;
Inc(Posn);
END;
ELSE Raise EConvertError.Create(S+
' некорректный Comp');
END;
END;
END;
end.