скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Класс для манипулирования списком вещественных чисел



Автор: Vitaly Sergienko

{ **** UBPFD *********** by delphibase.endimus.com ****
>> Класс для манипулирования списком вещественных чисел

Класс для манипулирования списком вещественных чисел
Класс TxFloatList позволяет оперировать динамическим списком вещественных
чисел (тип Double) двойной точности.

Применение аналогично использованию TStringList :-)

Ограничения
Проверенно на Delphi 6.0 + SP2.

Зависимости: Classes
Автор:       softland, softland@zmail.ru, Волгоград
Copyright:   Vitaly Sergienko (softland@zmail.ru)
Дата:        4 августа 2002 г.
***************************************************** }

(*
(c) Vitaly Sergienko (softland@zmail.ru)
created(10 Feb 1996)
lastmod(4 Aug 2002)

Базовая версия исходного кода взята из книги, название уже не помню :-( и обес-
печивала работу с целыми числами

ver 1.0.4

Класс для манипулирования списком вещественных чисел
  Класс TxFloatList позволяет оперировать динамическим списком вещественных
  чисел (тип Double) двойной точности.

Как можно применить
  Применение аналогично использованию TStringList :-)

Ограничения
  Проверенно на Delphi 6.0 + SP2.

Форматирование комментариев подготовлено для обработки исходников программой rjPasDoc
*)

unit floatlist;

interface

uses Classes;

const
  (* Минимальное значение для типа double *)
  _FLOAT_MIN_ = -1.1E4932;

  (* Максимальное значение для типа double *)
  _FLOAT_MAX_ = 1.1E4932;

  (* Точность в рабочих вычислениях *)
  _EPSILON_ = 0.00001;

  (* Константа возвращаемая при успешном завершении функции *)
  _OK_ = 1;

  (* Константа возвращаемая при неудачном завершении функции *)
  _ERROR_ = 0;

type

  (* Класс генерации exception при переполнении списка *)
  EOutOfRange = class(EListError);

  (* Класс обеспечивает создание, удаление, вставку и доступ к элементам динами-
     ческого списка вещественных чисел.
     Дополнительно поддерживается сортировка списка, поиск минимального и макси-
     мального значений в списке.
     Особенностью реализации списка является введение понятия несуществующего зна-
     чения "property Null". Данное свойство определяет значение, которое не участ-
     вует в операциях получения min и max списка.
     Второй особенностью списка является работа с определенной точностью, значение
     выведено в константу _EPSILON_.
     Поиск и сортировка осуществляются без использования свойства NULL и _EPSILON_
  *)
  TxFloatList = class(TPersistent)
  private
    FList: TList;
    FDuplicates: TDuplicates;
    FNULL: double;
    FMin: double;
    FMax: double;
    FSizeOfFloat: integer;
    FSorted: Boolean;
  protected
    procedure DefineProperties(Filer: TFiler); override;
    function GetCount(): integer;
    function GetItem(Index: integer): double;
    procedure SetItem(Index: integer; Value: double); virtual;
    procedure SetMin(Value: double);
    procedure SetMax(Value: double);
    procedure Sort(); virtual;
  public
    constructor Create();
    destructor Destroy(); override;
    procedure ReadMin(Reader: TReader);
    procedure WriteMin(Writer: TWriter);
    procedure ReadMax(Reader: TReader);
    procedure WriteMax(Writer: TWriter);
    procedure ReadFloats(Reader: TReader);
    procedure WriteFloats(Writer: TWriter);
    procedure SetSorted(Value: Boolean);
    procedure QuickSort(L, R: integer);
    function Find(N: double; var Index: integer): Boolean; virtual;
    function Add(Value: double): integer; virtual;
    procedure AddFloats(List: TxFloatList); virtual;
    procedure Assign(Source: TPersistent); override;
    procedure Clear(); virtual;
    procedure Delete(Index: integer); virtual;
    function Equals(List: TxFloatList): Boolean;
    procedure Exchange(Index1, Index2: integer); virtual;
    function IndexOf(N: double): integer; virtual;
    procedure Insert(Index: integer; Value: double); virtual;
    (* Помещает пустые значения в список начиная с позиции iFirst в количестве iCount *)
    function InsertNulls(iFirst, iCount: integer; _null: single): integer;
    procedure Move(CurIndex, NewIndex: integer); virtual;
    // определение max среди хранимых данных
    function FindMax(): double;
    // определение min среди хранимых данных
    function FindMin(): double;
    (* Заменяет все отрицательные значения на нулевое *)
    function ReplaceNegativeToNULL(): integer;
    (* Заменяет все значения ThisValue на ToValue, с точностью Prec *)
    function ReplaceValToVal(ThisValue, ToValue, Prec: double): integer;
    function ReplaceGreateToVal(ThisValue, ToValue, Prec: double): integer;
    function ReplaceLessToVal(ThisValue, ToValue, Prec: double): integer;
    (* Инвертирует знак всех значений*)
    function InvertValues(): integer;
    (* Меняет, инвертирует порядок всех элементов в списке *)
    function Reverse(): integer;
    property Duplicates: TDuplicates read FDuplicates write FDuplicates;
    property Count: integer read GetCount;
    property Items[Index: integer]: double read GetItem write SetItem; default;
    property Min: double read FMin write SetMin;
    property Max: double read FMax write SetMax;
    property Null: double read FNULL write FNULL;
    property Sorted: Boolean read FSorted write SetSorted;
  end;

  (********************************************************************)
implementation

uses WinTypes;

constructor TxFloatList.Create;
begin
  inherited Create;
  FList := TList.Create;
  FSizeOfFloat := SizeOf(double);
end;

destructor TxFloatList.Destroy;
begin
  Clear;
  FList.Free;
  inherited Destroy;
end;

procedure TxFloatList.Assign(Source: TPersistent);
begin
  if Source is TxFloatList then
  begin
    Clear;
    AddFloats(TxFloatList(Source));
  end
  else
    inherited Assign(Source);
end;

procedure TxFloatList.DefineProperties(Filer: TFiler);
begin
  Filer.DefineProperty('Min', ReadMin, WriteMin, min <> 0);
  Filer.DefineProperty('Max', ReadMax, WriteMax, FMax <> 0);
  Filer.DefineProperty('Floats', ReadFloats, WriteFloats, Count > 0);
end;

procedure TxFloatList.ReadMin(Reader: TReader);
begin
  FMin := Reader.ReadFloat;
end;

procedure TxFloatList.WriteMin(Writer: TWriter);
begin
  Writer.WriteFloat(FMin);
end;

procedure TxFloatList.ReadMax(Reader: TReader);
begin
  FMax := Reader.ReadFloat;
end;

procedure TxFloatList.WriteMax(Writer: TWriter);
begin
  Writer.WriteFloat(FMax);
end;

procedure TxFloatList.ReadFloats(Reader: TReader);
begin
  Reader.ReadListBegin(); (* Считывание маркера начала списка *)
  Clear; (* Очистка иекущего списка *)
  while not Reader.EndOfList do
    Add(Reader.ReadFloat()); (* Добавление к списку хранящихся чисед *)
  Reader.ReadListEnd(); (* Считывание маркера конца списка *)
end;

procedure TxFloatList.WriteFloats(Writer: TWriter);
var
  i: integer;
begin
  Writer.WriteListBegin(); (* Вписываем маркер начала списка *)
  for i := 0 to Count - 1 do
    Writer.WriteFloat(GetItem(I)); (* Запись всех чисел из списка в Writer *)
  Writer.WriteListEnd(); (* Вписываем маркер конца списка *)
end;

procedure TxFloatList.SetSorted(Value: Boolean);
begin
  if FSorted <> Value then
  begin
    if Value then
      Sort();
    FSorted := Value;
  end;
end;

function TxFloatList.GetCount: integer;
begin
  Result := FList.Count;
end;

function TxFloatList.GetItem(Index: integer): double;
begin
  Result := PDouble(FList.Items[Index])^;
end;

procedure TxFloatList.SetItem(Index: integer; Value: double);
begin
  { if ( FMin <> FMax ) and ( ( Value < Fmin ) or ( Value > FMax ) ) then
      raise EOutOfRange.CreateFmt( 'Value must be within %d..%d', [FMin, FMax]);}
  PDouble(FList.Items[Index])^ := Value;
end;

procedure TxFloatList.SetMin(Value: double);
var
  i: integer;
begin
  if Value <> FMin then
  begin
    for i := 0 to Count - 1 do
      if GetItem(i) < Value then
        raise EOutOfRange.CreateFmt('Unable to set new minimum value. ' + #13 +
          'List contains values below %d', [Value]);
    FMin := Value;
    if FMin > FMax then
      FMax := FMin;
  end;
end;

procedure TxFloatList.SetMax(Value: double);
var
  i: integer;
begin
  if Value <> FMax then
  begin
    for i := 0 to Count - 1 do
      if GetItem(i) > Value then
        raise EOutOfRange.CreateFmt('Unable to set new maximum value. '#13 +
          'List contains values above %d', [Value]);
    FMax := Value;
    if FMax < FMin then
      FMin := FMax;
  end;
end;

procedure TxFloatList.AddFloats(List: TxFloatList);
var
  i: integer;
begin
  for i := 0 to Pred(List.Count) do
    Add(List[i]);
end;

function TxFloatList.Add(Value: double): integer;
begin
  Insert(Count, Value);
  result := Count;
end;

procedure TxFloatList.Clear;
var
  i: integer;
begin
  for i := 0 to Pred(FList.Count) do
    Dispose(PDouble(FList.Items[i]));
  FList.Clear;
end;

procedure TxFloatList.Delete(Index: integer);
begin
  Dispose(PDouble(FList.Items[Index]));
  FList.Delete(Index);
end;

function TxFloatList.Equals(List: TxFloatList): Boolean;
var
  i, Count: integer;
begin
  Count := GetCount;
  if Count <> List.GetCount then
    Result := False
  else
  begin
    i := 0;
    while (i < Count) and (GetItem(i) = List.GetItem(i)) do
      INC(i);
    Result := i = Count;
  end;
end;

procedure TxFloatList.Exchange(Index1, Index2: integer);
begin
  FList.Exchange(Index1, Index2);
end;

function TxFloatList.Find(N: double; var Index: integer): Boolean;
var
  l, h, i: integer;
begin
  Result := False;
  l := 0;
  h := Count - 1;
  while l <= h do
  begin
    i := (l + h) shr 1;
    if PDouble(FList[i])^ < N then
      l := i + 1
    else
    begin
      h := i - 1;
      if PDouble(FList[i])^ = N then
      begin
        Result := True;
        if Duplicates <> dupAccept then
          l := i;
      end;
    end;
  end;
  Index := l;
end;

function TxFloatList.IndexOf(N: double): integer;
var
  i: integer;
begin
  Result := -1;
  if not Sorted then
  begin
    for i := 0 to Pred(GetCount) do
      if GetItem(i) = N then
      begin
        Result := i;
        exit;
      end;
  end
  else if Find(N, i) then
    Result := i;
end;

procedure TxFloatList.Insert(Index: integer; Value: double);
var
  P: PDouble;
begin
  //comment ad 12.04.2001 softland
  // if (FMin <> FMax) and (( Value < FMin ) or (Value > FMax )) then
  // raise EOutOfRange.CreateFmt( 'Value must be within %f..%f', [FMin, FMax ]);
  NEW(p);
  p^ := Value;
  FList.Insert(Index, P);
end;

procedure TxFloatList.Move(CurIndex, NewIndex: integer);
begin
  FList.Move(CurIndex, NewIndex);
end;

procedure TxFloatList.QuickSort(L, R: integer);
var
  i, j: integer;
  p: PDouble;
begin
  i := L;
  j := R;
  P := PDouble(FList[(L + R) shr i]);
  repeat
    while PDouble(FList[i])^ < P^ do
      INC(i);
    while PDouble(FList[j])^ > P^ do
      DEC(j);
    if i <= j then
    begin
      FList.Exchange(i, j);
      INC(i);
      DEC(j);
    end;
  until i > l;
  if L < j then
    QuickSort(L, j);
  if i < R then
    Quicksort(i, R);
end;

procedure TxFloatList.Sort();
begin
  if not Sorted and (FList.Count > 1) then
    QuickSort(0, FList.Count - 1);
end;

function TxFloatList.FindMax(): double; // определение max среди хранимых данных
var
  i: integer;
  v: double;
begin
  FMax := _FLOAT_MIN_;
  for i := 0 to Count - 1 do
  begin
    v := GetItem(i);
    if abs(v - FNULL) > _EPSILON_ then
      if v > FMax then
        FMax := v;
  end;
  if abs(FMax - _FLOAT_MIN_) < _EPSILON_ then
    FMax := FNULL;
  result := FMax;
end;

function TxFloatList.FindMin: double; //определение min среди хранимых данных
var
  i: integer;
  v: double;
begin
  { for i := 0 to Count-1 do
      if GetItem(i) <> FNULL then begin
        FMin := GetItem(i);
        break;
      end;}
  FMin := _FLOAT_MAX_;
  for i := 0 to Count - 1 do
  begin
    v := GetItem(i);
    if abs(v - FNULL) > _EPSILON_ then
      if v < FMin then
        FMin := v;
  end;
  if abs(FMin - _FLOAT_MAX_) < _EPSILON_ then
    FMin := FNULL;
  result := FMin;
end;

(* Заменяет все отрицательные значения на нулевое *)

function TxFloatList.ReplaceNegativeToNULL: integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to Count - 1 do
  begin
    if Items[i] < 0 then
    begin
      Items[i] := self.Null;
      inc(result);
    end;
  end;
end;

function TxFloatList.ReplaceValToVal(ThisValue, ToValue, Prec: double): integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to Count - 1 do
  begin
    if abs(Items[i] - ThisValue) < Prec then
    begin
      Items[i] := ToValue;
      inc(result);
    end;
  end;
end;

function TxFloatList.ReplaceLessToVal(ThisValue, ToValue, Prec: double):
  integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to Count - 1 do
  begin
    if Items[i] < ThisValue then
    begin
      Items[i] := ToValue;
      inc(result);
    end;
  end;
end;

function TxFloatList.ReplaceGreateToVal(ThisValue, ToValue, Prec: double):
  integer;
var
  i: integer;
begin
  result := 0;
  for i := 0 to Count - 1 do
  begin
    if Items[i] > ThisValue then
    begin
      Items[i] := ToValue;
      inc(result);
    end;
  end;
end;

function TxFloatList.InvertValues(): integer;
var
  i: integer;
begin
  result := _OK_;
  for i := 0 to Count - 1 do
    items[i] := -items[i];
end;

function TxFloatList.Reverse(): integer;
var
  i, j: integer;
begin
  result := _OK_;
  i := 0;
  j := Count - 1;
  repeat
    self.Exchange(i, j);
    inc(i);
    dec(j);
  until i >= j;
end;

(* Заполнение в заданных пределах значениями NULL
   Подразумевается положительное и возрастающее поведение глубины, т.е.
   0<STRT<STOP
   Еи _strt > текущего min или _stop < текущего максимума содержащегося в
   списке, то функция возвращает _ERROR_
   Еи _null не совпадает со значением принятым за NULL в списке, то это игнорируется
   Заполнение ведется с текущим шагом списка *)

function TxFloatList.InsertNulls(iFirst, iCount: integer; _null: single):
  integer;
var
  k: integer;
begin
  for k := 1 to iCount do
  begin
    Insert(iFirst, _null);
    inc(iFirst);
  end;
  result := _OK_;
end;

end.





Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook