【发布时间】:2013-01-27 13:38:57
【问题描述】:
我有一个非常简单的 3D 矢量类定义 TVector3D,以及一些用于实现 TVector3D.Normalise 函数的方法。如果我向Normalise 函数传递一个已经标准化的向量,我希望它返回我传递给它的向量。在这里我使用了Result := Self,但我得到了一些疯狂的回报。
控制台应用程序:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TVector3D = Class
public
x : Single;
y : Single;
z : Single;
constructor Create(x : Single;
y : Single;
z : Single);
function GetMagnitude() : Single;
function IsUnitVector() : Boolean;
function Normalise() : TVector3D;
end;
constructor TVector3D.Create(x : Single;
y : Single;
z : Single);
begin
Self.x := x;
Self.y := y;
Self.z := z;
end;
function TVector3D.GetMagnitude;
begin
Result := Sqrt(Sqr(Self.x) + Sqr(Self.y) + Sqr(Self.z));
end;
function TVector3D.IsUnitVector;
begin
if Self.GetMagnitude = 1 then
Result := True
else
Result := False;
end;
function TVector3D.Normalise;
var
x : Single;
y : Single;
z : Single;
MagnitudeFactor : Single;
begin
if IsUnitVector then
Result := Self
else
MagnitudeFactor := 1/(Self.GetMagnitude);
x := Self.x*MagnitudeFactor;
y := Self.y*MagnitudeFactor;
z := Self.z*MagnitudeFactor;
Result := TVector3D.Create(x,
y,
z);
end;
procedure TestNormalise;
var
nonUnitVector : TVector3D;
unitVector : TVector3D;
nUVNormed : TVector3D;
uVNormed : TVector3D;
begin
//Setup Vectors for Test
nonUnitVector := TVector3D.Create(1,
1,
1);
unitVector := TVector3D.Create(1,
0,
0);
//Normalise Vectors & Free Memory
nUVNormed := nonUnitVector.Normalise;
nonUnitVector.Free;
uVNormed := unitVector.Normalise;
unitVector.Free;
//Print Output & Free Memory
WriteLn('nUVNormed = (' + FloatToStr(nUVNormed.x) + ', ' + FloatToStr(nUVNormed.y) + ', ' + FloatToStr(nUVNormed.z) + ')');
nUVNormed.Free;
WriteLn('uVNormed = (' + FloatToStr(uVNormed.x) + ', ' + FloatToStr(uVNormed.y) + ', ' + FloatToStr(uVNormed.z) + ')');
uVNormed.Free;
end;
begin
try
TestNormalise;
Sleep(10000);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Normalise 适用于非单位向量,即IsUnitVector 返回 false。但是对于单位向量,例如(1,0,0),我没有返回自身,而是在之前存在非零的地方得到一个非常低的非零数字的结果,例如(8.47122...E-38,0,0)。
如果我通过调试器运行此程序,并在 Result := Self 行设置一个断点来评估 Self,Self 是 (1,0,0) 但结果变为 (Very Low Number,0,0)。 Very Low Number 每次运行程序时都会发生变化,但似乎总是在 E-38/E-39 附近。
我不明白为什么会这样。为什么会发生这种情况以及如何最好地更改我的 Normalise 函数以避免它。
【问题讨论】:
-
我会让向量成为记录而不是类,但是 YMMV。
-
您对
TVector3D.Normalise实现的想法要求TVector3D类型是引用计数接口而不是类。 -
我之前已经告诉过你,至少一次,要让这成为记录。我不明白你为什么不接受这个建议。
-
@DavidHeffernan 我认识到您使用记录进行编码的建议是合理的,我将继续这样做。但是,使用记录重新编码并不能帮助我理解为什么上面的代码给了我它的结果。如果您阅读了这个问题,这就是我在这里提出的问题。现在我知道了答案,我将用记录重新实现它。
-
很公平。但我看起来比这个问题更广泛。例如,我可以看到您创建了两个对象,但释放了四个。因为根据您的设计,
nUVNormed和nonUnitVector实际上指的是同一个对象。另一对也是如此。所以你可以在免费后访问,并且双倍免费。而这些问题会吞噬你。因此,我敦促您尽快开始使用记录,从而避免这些陷阱。我已经为你提供了一些代码来开始。这是该程序的代码:orcina.com/SoftwareProducts/OrcaFlex
标签: delphi delphi-xe3