请求提供一个简单的例子来使用TComplexMath类(包含源代码)

3
我正在使用Borland Delphi7进行Pascal编程。我下载了一个相当基本(也是免费的)的复杂数学函数源代码库,但不幸的是它并没有带有任何用法示例。由于我不太熟悉Pascal中的类,我认为我只需要一个简单的用法示例来让我入门。
任何示例都可以,即使是将两个数字相加的示例也可以让我入门。以下是我的尝试(非常糟糕)。我认为我的问题在于我不知道如何使用类构造函数。
uses ComplexMath in 'complexmath.pas'

var z1,z2,z3 : TComplexNumber;
begin
  z1.R:=1.0; z1.I:=2.0;
  z2.R:=3.0; z2.I:=-1.0;
  z3 := TComplexMath.Add(z1,z2);
end.

TComplexMath的完整源代码可以在此处获取:http://delphi.about.com/library/weekly/aa070103a.htm。我还将部分源代码剪切并粘贴在下面(请注意,该代码是完整文件,除了我明确指出已经被剪切的部分)。

TComplexMath部分源代码清单如下:

unit ComplexMath;

interface

uses Windows, SysUtils, Classes, Controls, Math;

type
  TComplexNumber = record
    R : single;
    I : single;
  end;

TComplexMath = class(TComponent)
  private
    { Private declarations }
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner : TComponent); override;

    function Add(C1, C2 : TComplexNumber) : TComplexNumber; overload;
    { Returns the complex sum of C1 and C2 }

    function Add(C1, C2, C3 : TComplexNumber) : TComplexNumber; overload;
    { Returns the complex sum of C1 and C2 and C3 }

    ... and a bunch more like this ...

implementation

procedure Register;
  begin
    RegisterComponents('delphi.about.com', [TComplexMath]);
  end;

constructor TComplexMath.Create(AOwner : TComponent);
  begin
    inherited Create(AOwner);
  end;

 function TComplexMath.Add(C1, C2 : TComplexNumber) : TComplexNumber;
   begin
     Result.R := C1.R + C2.R;
     Result.I := C1.I + C2.I;
   end;

    ... and a bunch more like this ...

end.

在经过一段时间的努力后,我最终剥离了类定义,并仅使用函数本身(就像简单的函数库)。虽然这对我有用,但我知道这不是此组件的预期使用方式。如果有人能向我展示如何按照原意简单地使用此类的例子,我将不胜感激。

2个回答

7

这个功能的预期用法是这样的:

var
  cm: TComplexMath;

  z, w, sum: TComplexNumber;
begin

  cm := TComplexMath.Create(Self) // or nil, can most likely be anything
  try
    sum := cm.Add(z, w); // Now sum is the sum of z and w
  finally
    cm.Free;
  end;

end;

您也可以在应用程序启动时(或单元初始化等)创建TComplexMath实例,并在应用程序的整个生命周期中使用它:

unit Unit1;

interface

var
  cm: TComplexMath;

...

implementation

procedure Test;
begin

  sum := cm.Add(z, w); // Now sum is the sum of z and w

end;

...

initialization

  cm := TComplexMath.Create(nil);

finialization

  cm.Free;

最后,由于它是一个组件,因此您可以在设计时将其拖放到表单上。该实例将被称为ComplexMath1,您可以在表单类中使用它,就像这样:

procedure TForm1.Button1Click(Sender: TObject);
var
  z, w, sum: TComplexNumber;    
begin
  sum := ComplexMath1.Add(z, w);
end;

我非常不喜欢这个类的设计。首先,您只需要一个实例,为什么不将函数作为类函数呢?实际上,为什么要使用类?最后,如果您使用现代版本的Delphi,可以使用高级记录和运算符重载,使得像z + w这样的操作在您的源代码中能够像整数一样工作,就像zw这样的简单类型一样!


cm := TComplexMath.Create(Nil) 对我来说是有效的,但出于某种原因,我无法使用参数Self。它给了我“未声明的标识符:Self”错误。这可能是因为我只在“控制台应用程序”中运行它,还是我遗漏了“uses”子句中所需的内容? - Stuart
1
@Stuart:nil也可以。什么是“owner”?当所有者被释放时,它所拥有的东西也会被释放。self表示类的当前实例,仅存在于方法中。因此,例如,如果您有一个表单和一个按钮,并双击该按钮,则会进入像procedure TForm1.Button1Click(...这样的方法,然后self将引用TForm1的当前实例,可能是Form1。但在这种情况下,所有者没有用于任何事情,因此您指定什么并不重要(除非您销毁它)。因此,nil(表示“没有所有者”)完全可以。 - Andreas Rejbrand
所以,“self”没有被定义,因为我只是一个控制台应用程序?{$APPTYPE CONSOLE} - Stuart
2
不,Self 在当前行不可用,因为当前行不在方法内(即不属于类的函数或过程,与当前实例一起工作)。 - Andreas Rejbrand
1
不,Self没有被定义,因为你的代码不在一个方法内。 - David Heffernan
显示剩余3条评论

7

我不会使用那段代码,因为我认为它非常薄弱。这是更好的替代方案:

type
  TComplex = record
  public
    class operator Implicit(const D: Double): TComplex;
    class operator Negative(const C: TComplex): TComplex;
    class operator Equal(const C1, C2: TComplex): Boolean;
    class operator NotEqual(const C1, C2: TComplex): Boolean;
    class operator Add(const C1, C2: TComplex): TComplex;
    class operator Add(const C: TComplex; const D: Double): TComplex;
    class operator Add(const D: Double; const C: TComplex): TComplex;
    class operator Subtract(const C1, C2: TComplex): TComplex;
    class operator Subtract(const C: TComplex; const D: Double): TComplex;
    class operator Subtract(const D: Double; const C: TComplex): TComplex;
    class operator Multiply(const C1, C2: TComplex): TComplex;
    class operator Multiply(const C: TComplex; const D: Double): TComplex;
    class operator Multiply(const D: Double; const C: TComplex): TComplex;
    class operator Divide(const C1, C2: TComplex): TComplex;
    class operator Divide(const C: TComplex; const D: Double): TComplex;
    class operator Divide(const D: Double; const C: TComplex): TComplex;
    function IsZero: Boolean;
    function IsNonZero: Boolean;
    function Conj: TComplex;
    function Sqr: TComplex;
    function Sqrt: TComplex;
    function Mag: Double;
    function SqrMag: Double;
  public
    r: Double;
    i: Double;
  end;

const
  ZeroComplex: TComplex = ();//initialise to zero;

class operator TComplex.Implicit(const D: Double): TComplex;
begin
  Result.r := D;
  Result.i := 0.0;
end;

class operator TComplex.Negative(const C: TComplex): TComplex;
begin
  Result.r := -C.r;
  Result.i := -C.i;
end;

class operator TComplex.Equal(const C1, C2: TComplex): Boolean;
begin
  Result := (C1.r=C2.r) and (C1.i=C2.i);
end;

class operator TComplex.NotEqual(const C1, C2: TComplex): Boolean;
begin
  Result := not (C1=C2);
end;

class operator TComplex.Add(const C1, C2: TComplex): TComplex;
begin
  Result.r := C1.r + C2.r;
  Result.i := C1.i + C2.i;
end;

class operator TComplex.Add(const C: TComplex; const D: Double): TComplex;
begin
  Result.r := C.r + D;
  Result.i := C.i;
end;

class operator TComplex.Add(const D: Double; const C: TComplex): TComplex;
begin
  Result.r := D + C.r;
  Result.i := C.i;
end;

class operator TComplex.Subtract(const C1, C2: TComplex): TComplex;
begin
  Result.r := C1.r - C2.r;
  Result.i := C1.i - C2.i;
end;

class operator TComplex.Subtract(const C: TComplex; const D: Double): TComplex;
begin
  Result.r := C.r - D;
  Result.i := C.i;
end;

class operator TComplex.Subtract(const D: Double; const C: TComplex): TComplex;
begin
  Result.r := D - C.r;
  Result.i := -C.i;
end;

class operator TComplex.Multiply(const C1, C2: TComplex): TComplex;
begin
  Result.r := C1.r*C2.r - C1.i*C2.i;
  Result.i := C1.r*C2.i + C1.i*C2.r;
end;

class operator TComplex.Multiply(const C: TComplex; const D: Double): TComplex;
begin
  Result.r := C.r*D;
  Result.i := C.i*D;
end;

class operator TComplex.Multiply(const D: Double; const C: TComplex): TComplex;
begin
  Result.r := D*C.r;
  Result.i := D*C.i;
end;

class operator TComplex.Divide(const C1, C2: TComplex): TComplex;
var
  R, Denominator: Double;
begin
  if abs(C2.r)>=abs(C2.i) then begin
    R := C2.i/C2.r;
    Denominator := C2.r+R*C2.i;
    Result.r := (C1.r+R*C1.i)/Denominator;
    Result.i := (C1.i-R*C1.r)/Denominator;
  end else begin
    R := C2.r/C2.i;
    Denominator := C2.i+R*C2.r;
    Result.r := (C1.r*R+C1.i)/Denominator;
    Result.i := (C1.i*R-C1.r)/Denominator;
  end;
end;

class operator TComplex.Divide(const C: TComplex; const D: Double): TComplex;
begin
  Result := C*(1.0/D);
end;

class operator TComplex.Divide(const D: Double; const C: TComplex): TComplex;
var
  R, Denominator: Double;
begin
  if abs(C.r)>=abs(C.i) then begin
    R := C.i/C.r;
    Denominator := C.r+R*C.i;
    Result.r := D/Denominator;
    Result.i := -R*Result.r;
  end else begin
    R := C.r/C.i;
    Denominator := C.i+R*C.r;
    Result.i := -D/Denominator;
    Result.r := -R*Result.i;
  end;
end;

function TComplex.IsZero: Boolean;
begin
  Result := Self=ZeroComplex;
end;

function TComplex.IsNonZero: Boolean;
begin
  Result := Self<>ZeroComplex;
end;

function TComplex.Conj: TComplex;
begin
  Result.r := r;
  Result.i := -i;
end;

function TComplex.Sqr: TComplex;
begin
  Result := Self*Self;
end;

function TComplex.Sqrt: TComplex;
var
  x, y, v, w: Double;
begin
  if IsZero then begin
    Result := ZeroComplex;
  end else begin
    x := abs(r);
    y := abs(i);
    if x>=y then begin
      v := y/x;
      w := System.Sqrt(x)*System.Sqrt(0.5*(1.0+System.Sqrt(1.0+v*v)));
    end else begin
      v := x/y;
      w := System.Sqrt(y)*System.Sqrt(0.5*(v+System.Sqrt(1.0+v*v)));
    end;
    if r>=0.0 then begin
      Result.r := w;
      Result.i := i/(2.0*w);
    end else begin
      if i>=0.0 then begin
        Result.i := w;
      end else begin
        Result.i := -w;
      end;
      Result.r := i/(2.0*Result.i);
    end;
  end;
end;

function TComplex.Mag: Double;
var
  x, y, Temp: Double;
begin
  x := abs(r);
  y := abs(i);
  if x=0.0 then begin
    Result := y;
  end else if y=0.0 then begin
    Result := x;
  end else if x>y then begin
    Temp := y/x;
    Result := x*System.Sqrt(1.0+Temp*Temp);
  end else begin
    Temp := x/y;
    Result := y*System.Sqrt(1.0+Temp*Temp);
  end;
end;

function TComplex.SqrMag: Double;
begin
  Result := System.Sqr(r) + System.Sqr(i);
end;

这里使用运算符重载来实现+, -, */操作符。您会发现基于这个TComplex记录的代码比您在问题中提到的组件更加表达清晰。
虽然您链接的代码实现了更多功能,但很容易通过扩展此答案中的记录来添加更多功能。
当然,由于您使用的是Delphi 7,所以此答案中的代码对您没有帮助。这是因为运算符重载直到后来才被引入。如果要进行任何严肃的数学计算,需要使用运算符重载使代码易读。

1
+1. 我正准备在我的答案中加入一个指向你的 TVector2D 记录的链接。现在我想我不必这样做了!当然,才是正确的样子!忘记 About.com 上的代码吧。 - Andreas Rejbrand
@LURD 在从 D6 升级到 D2010 后,我做的第一件事就是将所有的数学代码(而且有很多)转换为操作重载记录,就像这样。这对我们代码的可读性产生了巨大的影响。 - David Heffernan
实际上,我非常喜欢这种特定的语法糖。 - Andreas Rejbrand
2
是的,@Stuart,在D7中这是行不通的。但我忍不住要发布这个。它对于任何使用现代Delphi的人都很有用。即使你应该放弃那个无意义的类。在那里不需要使用类。只需编写一些操作记录的函数即可。 - David Heffernan
太好了,我终于有理由安装它了。 :) - Stuart
显示剩余13条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接