在Delphi中ABS功能失败

时间:2012-08-13 06:55:02

标签: delphi

在Delphi6或Delphi 2010中,声明两个Currency类型的变量(vtemp1,vtemp2),并为它们提供0.09的值。 使用ABS功能嵌入其中一个变量并将其与另一个进行比较。 您希望比较产生积极的结果作为编译器 watch显示abs(vtemp1)和vtemp2的相同值。 奇怪的是if语句失败!!!

注意: - 这个问题只有在处理时才会遇到 数字0.09(尝试其他几个接近的值显示正常结果) - 将变量解释为Double而不是货币,问题就不复存在了。

3 个答案:

答案 0 :(得分:16)

我认为原因是类型转换。 Abs()函数会返回real个结果,因此currency变量会转换为real。看看文档:

  

Currency是一种定点数据类型,可最大限度地减少舍入错误   货币计算。在Win32平台上,它存储为缩放   64位整数,隐式显示最后四位有效数字   代表小数位。当与其他真实类型混合时   赋值和表达式,货币值自动分配   或乘以10000。

所以货币是固定的,而实际是浮点数。 您的问题的示例代码是:

program Project3;
{$APPTYPE CONSOLE}

const VALUE = 0.09;
var a,b  : currency;
begin
    a := VALUE;
    b := VALUE;

    if a = Abs(b) then writeln('equal')
    else writeln('not equal', a - Abs(b));

    readln;
end.
由于类型转换,

生成不等于的结果;

  

编译器监视显示abs(vtemp1)和vtemp2

的相同值

尝试添加x : real,然后致电x := abs(b);,将x添加到观察列表,选择它并按Edit watch,然后选择浮点。 X变为0.899...967

不仅0.09值产生这样的结果。您可以尝试使用此代码进行检查:

    for i := 0 to 10000 do begin
        a := a + 0.001;
        b := a;
        if a <> abs(b) then writeln('not equal', a);
    end;

所以,如果你需要货币变量的绝对值 - 就这么做吧。不要使用浮点abs()

    function Abs(x : Currency):Currency; inline;
    begin
        if x > 0 then result := x
        else result := -x;
    end;

答案 1 :(得分:6)

稍微澄清一下。如果比较浮动值,则会出现“问题”:

var
  A: Currency;

begin
  A:= 0.09;
  Assert(A = Abs(A));
end;

这是因为Abs(A)返回一个浮点值,A = Abs(A)实现为浮点数比较。

如果比较货币值,我无法重现它:

var
  A, B: Currency;
begin
  A:= 0.09;
  B:= Abs(A);
  Assert(A = B);
end;

但是第二个样本也是一个潜在的错误,因为B:= Abs(A)内部是浮点除法/乘以10000,舍入为货币(int64),并且取决于FPU舍入模式。


我创建了一个qc report #107893,它已被打开。

答案 2 :(得分:2)

我刚刚发现Delphi XE2 Abs 功能不会使货币类型超载的困难方法。

请参阅Delphi XE2 docwiki

这些是abs

支持的唯一类型
  • 功能Abs(X :):真实;超载;
  • function Abs(X :):Int64;超载;
  • function Abs(X :):整数;过载;
相关问题