⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vector.~pas

📁 以面向对象方法实现的数值算法类库
💻 ~PAS
字号:
{-------------------------------------------------------------------------------
2003.08.11 定义向量类及相关运算
以基本类定义为基础,定义向量类。该类能够与传统的数据类型进行方便的转换。
--------------------------------------------------------------------------------
2004.07.03
  向量与矩阵的乘法如何定义?列向量?还是行向量?
--------------------------------------------------------------------------------
2003.08.20
  移动平均:开头或结尾的点,有几个就平均几个。
  求离散的差分:前差(i-(i-1))
--------------------------------------------------------------------------------
2003.08.14 实现求导、牛顿迭代
--------------------------------------------------------------------------------
2003.08.13 向量的移动:左移、右移;带参数,表示循环与否(缺省情况是循环,否则补0)。
-------------------------------------------------------------------------------}
unit Vector;

interface

uses classes, MathTypes, DB, Series;

Type

  TVectorStyle = (RowVector, ColumnVector);

  TVector = class
  protected
    FData:          TFloatArray;               // 数据
    FCount:         integer;                   // 数组的大小
    FVectorStyle:   TVectorStyle;              // 向量的类型(行向量、列向量(缺省))
    {--------------------------------------------------------------------------}
    FFormat:        string;                    // 显示格式
    {--------------------------------------------------------------------------}
    FErrorLimit:    double;                    // 误差限
    FMaxIterations: Integer;                   // 最大迭代次数
    FRoot:          double;                    // 根
    {--------------------------------------------------------------------------}
    FDataSet:       TDataSet;                  // 数据库
    FStartField:    Integer;                   // 首字段ID
  public
    { 构造与析构方法-----------------------------------------------------------}
    constructor Create;
    destructor  Destroy; override;
    { 数据显示 ----------------------------------------------------------------}
    function    AsString: string;
    { 数据赋值 ----------------------------------------------------------------}
    procedure   CopyFrom(Source: TVector);
    procedure   CopyFromArray(x: array of double);
    procedure   LoadFromDatabase(ADataSet: TDataSet; FieldID: integer = 0;
                                 Start: integer = 0; nCount: integer = -1);
                                 overload;
    procedure   LoadFromDatabase; overload;
    { 数据维护 ----------------------------------------------------------------}
    function    LeftCopy(N: integer): TVector;
    procedure   Resize(NCount: integer);
    { 常见的数值方法 ----------------------------------------------------------}
    function    Average: double;              // 平均值
    function    Value(x: double): double;     // 多项式求值
    function    Derivative: TVector;          // 多项式的导数
    procedure   Transpose;
    { 有方程求根算法-----------------------------------------------------------}
    function    NewtonIteration: double;      // 牛顿迭代法求根
    { 有关统计的算法-----------------------------------------------------------}
    function    MovingAverage(N: integer=3): TVector;                    // 移动平均
    function    GetMinIndex: integer;                                    // 找极小值
    function    GetMaxIndex: integer;                                    // 找极大值
    function    GetAbsMaxIndex: integer;                                 // 找绝对极大值
    function    GetLocalAbsMaxIndex(FirstID, LastID: integer): integer;  // 找局部绝对极大值
    function    GetLocalMaxIndex(FirstID, LastID: integer): integer;     // 找局部极大值
    function    GetLocalMinIndex(FirstID, LastID: integer): integer;     // 找局部极小值

  published
    property Count: integer read FCount write Resize;
    property Values: TFloatArray read FData write FData;
    property DisplayFormat: string read FFormat write FFormat;
    property ErrorLimit: double read FErrorLimit write FErrorLimit;             // 误差限
    property MaxIterations: Integer read FMaxIterations write FMaxIterations;   // 最大迭代次数
    property Root: double read FRoot write FRoot;                               // 根
    property Style: TVectorStyle read FVectorStyle write FVectorStyle;          // 向量类型

  end;

  procedure ShowVectorAsSeries(Vx,Vy: TVector; aSeries: TCustomSeries;
                               StartIndex: integer = 0;   nCount: integer = -1);

implementation

uses math, sysutils, dialogs;

{ TVector }

procedure TVector.CopyFromArray(x: array of double);
Var
    i,N: integer;
begin
    N := Length(x);
    Resize(N);
    for i:=0 to N-1 do FData[i] := x[i];
end;

procedure TVector.CopyFrom(Source: TVector);
Var
    i: integer;
begin
    if Source is TVector then begin
      Resize((Source as TVector).FCount);
      for i:=0 to FCount-1 do FData[i] := (Source as TVector).Values[i];
    end;
end;

function TVector.AsString: string;
Var
    i: Integer;
begin
    Result := '';
    for i:=0 to FCount-1 do
      if Result='' then
        Result := Format(FFormat,[FData[i]])
      else
        Result := Result + Format(' + ' + FFormat+' x^%d',[FData[i],i]);
end;

function TVector.Average: double;
Var
    r: double;
    i: integer;
begin
    r := 0;
    for i:=0 to FCount-1 do r := r + FData[i];
    Result := r / FCount;
end;

constructor TVector.Create;
begin
    inherited Create;
    FData := nil;
    FFormat := '%.4f';
    FErrorLimit := 1e-5;           // 误差限
    FMaxIterations := 1000;        // 最大迭代次数
    FRoot := 0;                    // 根
    FVectorStyle := ColumnVector;  // 缺省是列向量 
end;

// 求多项式的导数
function TVector.Derivative: TVector;
Var
    i: integer;
begin
    Result := TVector.Create;
    if FCount>1 then begin
      Result.Resize (FCount-1);     // 多项式的大小
      // 计算一阶导数
      for i:=0 to FCount-2 do Result.FData[i] := FData[i+1] * (i+1);
    end else begin
      Result.Resize(1);
      Result.FData[0] := 0;
    end;
end;

destructor TVector.Destroy;
begin
    FData := nil;
    inherited;
end;

function TVector.GetAbsMaxIndex: integer;
Var
    tmp: double;
    i,k: integer;
begin
    tmp := abs(FData[0]);
    k := 0;
    for i:=1 to FCount-1 do begin
      if tmp<abs(FData[i]) then begin
        tmp := abs(FData[i]);
        k := i;
      end;
    end;
    Result := k;
end;

function TVector.GetLocalAbsMaxIndex(FirstID, LastID: integer): integer;
Var
    tmp: double;
    i,k: integer;
begin
    tmp := abs(FData[FirstID]);
    k := FirstID;
    for i:=FirstID+1 to LastID do begin
      if tmp<abs(FData[i]) then begin
        tmp := abs(FData[i]);
        k := i;
      end;
    end;
    Result := k;
end;

function TVector.GetLocalMaxIndex(FirstID, LastID: integer): integer;
Var
    tmp: double;
    i,k: integer;
begin
    tmp := FData[FirstID];
    k := FirstID;
    for i:=FirstID+1 to LastID do begin
      if tmp<FData[i] then begin
        tmp := FData[i];
        k := i;
      end;
    end;
    Result := k;
end;

function TVector.GetLocalMinIndex(FirstID, LastID: integer): integer;
Var
    tmp: double;
    i,k: integer;
begin
    tmp := FData[FirstID];
    k := FirstID;
    for i:=FirstID+1 to LastID do begin
      if tmp>FData[i] then begin
        tmp := FData[i];
        k := i;
      end;
    end;
    Result := k;
end;

function TVector.GetMaxIndex: integer;
Var
    tmp: double;
    i,k: integer;
begin
    tmp := FData[0];
    k := 0;
    for i:=1 to FCount-1 do begin
      if tmp<FData[i] then begin
        tmp := FData[i];
        k := i;
      end;
    end;
    Result := k;
end;

function TVector.GetMinIndex: integer;
Var
    tmp: double;
    i,k: integer;
begin
    tmp := FData[0];
    k := 0;
    for i:=1 to FCount-1 do begin
      if tmp>FData[i] then begin
        tmp := FData[i];
        k := i;
      end;
    end;
    Result := k;
end;

function TVector.LeftCopy(N: integer): TVector;
Var
    i: Integer;
begin
    Result := TVector.Create;
    Result.Resize(N);
    for i:=0 to N-1 do Result.Values[i] := FData[i];
end;

procedure TVector.LoadFromDatabase(ADataSet: TDataSet; FieldID: integer = 0;
        Start: integer = 0; nCount: integer = -1);
Var
    i,N: integer;
begin
    N := ADataSet.RecordCount;
    if nCount>0 then Resize(nCount)
    else             Resize(N);
    ADataSet.FindFirst;
    for i:=0 to Start-1 do ADataSet.Next;
    if nCount<0 then begin
      for i:=0 to N-1 do
        if NOT ADataSet.Eof then begin
          FData[i] := ADataSet.Fields[FieldId].AsFloat;
          ADataSet.Next;
        end else break;
    end else begin
      for i:=0 to nCount-1 do
        if NOT ADataSet.Eof then begin
          FData[i] := ADataSet.Fields[FieldId].AsFloat;
          ADataSet.Next;
        end else break;
    end;
end;

function TVector.MovingAverage(N: integer): TVector;
Var
    L, R, i, Z, j: integer;
    y: TVector;
    a: double;
begin
    if not odd(N) then N := N+1;
    Z := N div 2;
    y := TVector.Create;
    y.Resize(FCount);
    for i:=0 to FCount-1 do begin
      a := 0;
      // 左端
      L := 0;
      if i>=Z then begin
        for j:=i-Z to i-1 do begin
          a := a + FData[j];
          inc(L);
        end;
      end else begin
        for j:=0 to i-1 do begin
          a := a + FData[j];
          inc(L);
        end;
      end;
      // 中心点
      a := a + FData[i];
      // 右端
      R := 0;
      if i<FCount-Z then begin
        for j:=i+1 to i+Z do begin
          a := a + FData[j];
          inc(R);
        end;
      end else begin
        for j:=i+1 to FCount-1 do begin
          a := a + FData[j];
          inc(R);
        end;
      end;
      y.FData[i] := a / (L + R + 1);
    end;
    Result := y;
end;

function TVector.NewtonIteration: double;
Var
    i: Integer;
    xn, xn_1, e: double;
    dp: TVector;
begin
    // 计算一阶导数
    dp := Derivative;
    // 开始迭代
    i := 0;
    xn_1 := FRoot;
    Repeat
      xn := xn_1 - poly(xn_1, FData) / poly(xn_1, dp.FData);
      e := abs(xn - xn_1);
      inc(i);
      if e >= FErrorLimit then xn_1 := xn;
    Until (i>FMaxIterations) or (e < FErrorLimit);
    if i>FMaxIterations then showmessage('牛顿迭代不收敛!');
    FRoot := (xn + xn_1) / 2;
    Result := FRoot;
end;

procedure TVector.Resize(NCount: integer);
begin
    if NCount<>FCount then begin
      FData := nil;
      SetLength(FData, NCount);
      FCount := NCount;
    end;
end;

function TVector.Value(x: double): double;
begin
    Result := Poly(x, FData);
end;

procedure ShowVectorAsSeries(Vx,Vy: TVector; aSeries: TCustomSeries;
                            StartIndex: integer = 0;   nCount: integer = -1);
Var
    i,N: integer;
begin
    aSeries.Clear;
    if nCount>0 then N := StartIndex + nCount
    else             N := StartIndex + Vx.Count;
    for i:=StartIndex to N-1 do aSeries.AddXY(Vx.Values[i], Vy.Values[i]);
end;

procedure TVector.Transpose;
begin
    if FVectorStyle = ColumnVector then FVectorStyle := RowVector
    else                                FVectorStyle := ColumnVector;
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -