【问题标题】:How to compare double in delphi?如何在delphi中比较double?
【发布时间】:2011-08-31 15:46:55
【问题描述】:

我们面临数据类型双重比较的问题:

if(p > pmax) then
begin
  Showmessage('');
end

如果两个值都是 100(p=100 和 pmax = 100),那么它也在 if 子句中。

【问题讨论】:

标签: delphi types


【解决方案1】:

Math.pas 单元包括处理浮动类型比较和相等的函数,例如 SameValue()IsZero()CompareValue()

const
  EPSILON = 0.0000001;
begin    
  if CompareValue(p, pMax, EPSILON) = GreaterThanValue then
    ShowMessage('p greater than pMax');

常量GreaterThanValue在Types.pas中定义

如果您要比较非常大的值,您不应为 epsilon 使用常量,而应根据您要比较的值计算 epsilon 值。

var
  epsilon: double;
begin    
  epsilon := Max(Min(Abs(p), Abs(pMax)) * 0.000001, 0.000001);
  if CompareValue(p, pMax, epsilon) = GreaterThanValue then
    ShowMessage('p greater than pMax');

请注意,如果您使用CompareValue(a, b, 0) 或在XE2 及更高版本中使用CompareValue(a, b),Delphi 会自动为您填写一个好的epsilon。

来自德尔福Math单位:

function SameValue(const A, B: Extended; Epsilon: Extended): Boolean;
begin
  if Epsilon = 0 then
    Epsilon := Max(Min(Abs(A), Abs(B)) * ExtendedResolution, ExtendedResolution);
  if A > B then
    Result := (A - B) <= Epsilon
  else
    Result := (B - A) <= Epsilon;
end;

从 Delphi XE2 开始,现在所有这些函数都有重载,不需要 epsilon 参数而是为您计算一个(类似于为 epsilon 传递 0 值)。为了代码清晰,我建议调用这些更简单的函数并让 Delphi 处理 epsilon。

不使用没有 epsilon 参数的重载的唯一原因是当性能至关重要并且您希望避免重复计算 epsilon 的开销时。

【讨论】:

  • 非常感谢..看起来它正在工作..昨天我试过这个但我不知道 Types.pas..
  • -100 用于使用 epsilon 的固定值,我已经编辑了答案来解决问题。
  • 我相信,如果有人使用固定的 Epsilon 并导致他们出现问题,那么他们的问题不是 Epsilon,而是 Double/Extended 不再精确满足他们的需求这一事实。就个人而言,我将在工作中继续使用 Epsilon 的固定值。一旦我使用的扩展变量的值达到折扣超过 0.005 美元的程度,Epsilon 将是我最不关心的问题。
  • @Johan: -100 如果我可以编辑更改的内容。如果您不同意答案,请发布您自己的答案并对您认为错误的答案投反对票。如果您有语法或格式更改,请编辑。如果您不同意答案,请投反对票。将其修改为不同的含义不是应该进行的编辑。
  • 我觉得永远不会太强烈。如果您知道您的数据将始终在固定范围内,为什么要在每次计算中增加重新计算 epsilon 的开销。计算一次适当的 epsilon,然后将其设为 epsilon 常数。
【解决方案2】:

比较双打有几个问题。一个问题是,由于四舍五入,您所看到的并不完全是您所得到的。您可以有 99.999999996423 和 100.00000000001632,它们都四舍五入到 100,但它们不相等。

解决方案是使用一个边距,这样,如果两个 Doubles 的差异在边距之内,您就可以接受它们相等。

您可以使用边距作为可选参数来创建 IsEqual 函数:

function IsEqual(const ANumber1, ANumber2: Double; const AMargin: Double = cMargin): Boolean;
begin
  Result := Abs(ANumber1-ANumber2) <= AMargin;
end;

【讨论】:

  • 请注意,您的正确解决方案已在 Math.pas 中作为“SameValue”提供。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-20
  • 2012-08-26
  • 2018-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多