gpt4 book ai didi

delphi - Embarcadero RAD Studio XE2 调试器中显示的局部变量的准确度是多少?显然1不等于1

转载 作者:行者123 更新时间:2023-12-03 15:04:42 27 4
gpt4 key购买 nike

进行以下记录:

TVector2D = record
public
class operator Equal(const V1, V2: TVector2D): Boolean;
class operator Multiply(const D: Accuracy; const V: TVector2D): TVector2D;
class operator Divide(const V: TVector2D; const D: Accuracy): TVector2D;
class function New(const x, y: Accuracy): TVector2D; static;
function Magnitude: Accuracy;
function Normalised: TVector2D;
public
x, y: Accuracy;
end;

方法定义为:

class operator TVector2D.Equal(const V1, V2: TVector2D): Boolean;
var
A, B: Boolean;
begin
Result := (V1.x = V2.x) and (V1.y = V2.y);
end;

class operator TVector2D.Multiply(const D: Accuracy; const V: TVector2D): TVector2D;
begin
Result.x := D*V.x;
Result.y := D*V.y;
end;

class operator TVector2D.Divide(const V: TVector2D; const D: Accuracy): TVector2D;
begin
Result := (1.0/D)*V;
end;

class function TVector2D.New(const x, y: Accuracy): TVector2D;
begin
Result.x := x;
Result.y := y;
end;

function TVector2D.Magnitude;
begin
RESULT := Sqrt(x*x + y*y);
end;

function TVector2D.Normalised: TVector2D;
begin
Result := Self/Magnitude;
end;

和一个常数:

  const
jHat2D : TVector2D = (x: 0; y: 1);

我希望 (jHat2D = TVector2D.New(0,0.707).Normalized)Boolean 值为 True。但结果却是False

在调试器中 TVector2D.New(0,0.707).Normalized.y 显示为 1

http://i.imgur.com/9XhQqgD.png

不可能正好为 1,否则 (jHat2D = TVector2D.New(0,0.707).Normalized)Boolean 值将为

有什么想法吗?

编辑

Accuracy 是一个Type,定义为:Accuracy = Double

最佳答案

假设AccuracyDouble类型的同义词,这是调试器可视化浮点值的一个错误。由于 float 内部表示的固有问题,v1.Yv2.Y 的值略有不同,尽管两者都近似于1.

添加v1.yv2.y的监视。确保将这些监视值配置为表示为“浮点”值,并将位数设置为 18,以获取最大细节。

在断点处您将看到:

v1.y      = 1
v2.y = 0.999999999999999889

(whosrdaddy 在问题评论中提供了上述简短版本,但我保留了调查的详细形式 - 请参阅结论之后的行下方 - 作为它可能在其他类似的情况下有用并且具有潜在的兴趣)

结论

虽然严格来说调试器可视化是不正确的(或者充其量是误导性的),但它们仍然几乎正确。 :)

接下来的问题是您是否需要严格准确度或在一定容差范围内的准确度。如果是后者,那么您可以使用 SameValue() 以及定义的适合您所需准确度的 EPSILON

否则,您必须接受这样的事实:在调试代码时,您不能依赖调试器将调试中涉及的值表示为代码本身所依赖的准确度。

选项:自定义调试可视化本身

或者,您可能希望调查 creating a custom debug visualisation使您的 TVector2D 类型能够按照代码中使用的精度来表示 x/y 值。

对于使用 FloatToStr() 的此类可视化,请使用 Format() 以及带有适当小数位数的 %f 格式说明符。例如下面的调用产生通过观察上述变量获得的结果:

Format('%.18f', [v2.y]);

// Yields 0.999999999999999889
<小时/>

原始调查的长版本

我修改了 Equal 运算符,以允许我检查两个值 v1.yv2.y 的内部表示:

type
PAccuracy = Accuracy;

class operator TVector2D.Equal(const V1, V2: TVector2D): Boolean;
var
A, B: Boolean;
ay, by: PAccuracy;
begin
ay := @V1.y;
by := @V2.y;

A := (V1.x = V2.x);
B := (V1.y = V2.y);

result := A and B;
end;

通过在调试器中设置监视来提供 ay^by^内存转储,我们看到这两个值在内部表示非常不同:

v1.y   : $3f f0 00 00 00 00 00 00
v2.y : $3f ef ff ff ff ff ff ff

注意:由于英特尔的 Little Endian 特性,与上述实际值相比,监视值结果中的字节顺序是相反的。

然后我们可以通过将带有这些内部表示的 double 传递给FloatToStr()来测试假设:

var
a: Double;
b: Double;
ai: Int64 absolute a;
bi: Int64 absolute b;

begin
ai := $3ff0000000000000;
bi := $3fefffffffffffff;

s := FloatToStr(a) + ' = ' + FloatToStr(b);

// Yields 's' = '1 = 1';
end;

因此我们可以得出结论,B的评估是正确的。 v1.yv2.y 不同。调试器对 Double 值的表示不正确(或者充其量是误导性的)。

通过更改 B 的表达式以使用 SameValue(),我们可以确定所涉及值之间的偏差:

uses
Math;

const
EPSILON = 0.1;

B := SameValue(V1.y, V2.y, EPSILON);

通过逐渐减小 EPSILON 的值,我们发现 v1.yv2.y 的差异小于 0.000000000000001 自:

EPSILON = 0.000000000000001;   // Yields B = TRUE
EPSILON = 0.0000000000000001; // Yields B = FALSE

关于delphi - Embarcadero RAD Studio XE2 调试器中显示的局部变量的准确度是多少?显然1不等于1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29972796/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com