Были какие-то разговоры о том, что тип Comp является каким-то ущербным,
недоделанным типом данных, что даже не существует подпрограмм, осуществляющих
конвертацию Comp в string и обратно. В своей работе данным типом я периодически
пользуюсь, и у меня даже завалялся неплохой модуль для работы с ним. Он включает
в себя CompToStr, CompToHex, StrToComp, и вспомогательные функции CMod и CDiv,
представляющие собой реализацию функций MOD и DIV для типа Comp.
Я обнаружил кое-что интересное в работе функций CMod и CDiv. Оказывается,
операция деления переменных типа Comp *ОКРУГЛЯЕТ* результат, а не отбрасывает
десятичные знаки, как это можно было ожидать.
Также я обнаружил некоторые странности на границах диапазона Comp. Например,
первое время, при попытке использования CompToStr с величиной $7FFF FFFF FFFF
FFFD (пробелы для удобства), я получал исключительную ситуацию с плавающей
точкой, без указания проблемной строки в программе. Зато вторичная попытка
исключения не вызывала. Потрясающе странно! Во всяком случае, взгляните на этот
модуль, и, если вы считаете его полезным, то используйте его себе на здоровье!
Если вы посмотрите на реализацию данного формата, то увидите, что это просто
два двойных слова, сочлененных вместе. Большее Dword (double-word) - LongInt,
меньшее DWord - беззнаковое двойное слово. Я действительно не знаю, почему
Delphi и Object Pascal рассматривают Comp как реальное число с плавающей
точкой??
unit Compfunc;
interfacetype
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;
implementationuses 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;
beginif C > MaxComp thenraise ERangeError.Create('Comp слишком велик для преобразования в string');
if C > 0 then
Result := '-' + CompToStr(-C)
elsebegin
Result := '';
Posn := 0;
whileTRUEdobegin
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;
beginif (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;
beginif S[1] = '-' then
Result := -StrToComp(Copy(S, 2, Length(S) - 1))
elseif S[1] = '$' then{Шестнадцатиричная строка}tryif Length(S) > 9 thenbegin{Если строка некорректна, исключение сгенерирует 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))
endelsebegin{Если строка некорректна, исключение сгенерирует StrToInt}
Result := StrToInt(S);
if Result < 0 then
Result := Result + Two32;
end;
excepton EConvertError doraise
EConvertError.Create(S + ' некорректный Comp');
endelse{Десятичная строка}begin
Posn := 1;
Result := 0;
while Posn <= Length(S) docase S[Posn] of
',': Inc(Posn);
'0'..'9':
begin
Result := Result * 10 + Ord(S[Posn]) - $30;
Inc(Posn);
end;
elseraise EConvertError.Create(S +
' некорректный Comp');
end;
end;
end;
end.
Статья Преобразования типа Comp в тип Str раздела Синтаксис Преобразования может быть полезна для разработчиков на Delphi и FreePascal.
Комментарии и вопросы
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.