Delphi中ABS函数失效
在Delphi6或Delphi 2010中,声明两个Currency类型的变量(vtemp1、vtemp2),并为它们提供一个0.09的值。 将其中一个变量嵌入ABS函数,并将其与另一个进行比较。 作为编译器,您会期望比较产生积极的结果 手表显示的abs(vtemp1)和vtemp2的值相同。 奇怪的是if语句失败了 注: -只有在处理 数字0.09(尝试其他几个近似值显示正常结果)Delphi中ABS函数失效,delphi,Delphi,在Delphi6或Delphi 2010中,声明两个Currency类型的变量(vtemp1、vtemp2),并为它们提供一个0.09的值。 将其中一个变量嵌入ABS函数,并将其与另一个进行比较。 作为编译器,您会期望比较产生积极的结果 手表显示的abs(vtemp1)和vtemp2的值相同。 奇怪的是if语句失败了 注: -只有在处理 数字0.09(尝试其他几个近似值显示正常结果) -将变量声明为Double而不是currency,问题就不存在了 我认为原因是类型转换Abs()函数返回real
-将变量声明为Double而不是currency,问题就不存在了 我认为原因是类型转换
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
添加到手表列表中,选择它并按编辑手表
,然后选择浮点<代码>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;
稍微澄清一下。如果比较浮点值,则会出现“问题”:
var
A: Currency;
begin
A:= 0.09;
Assert(A = Abs(A));
end;
var
A, B: Currency;
begin
A:= 0.09;
B:= Abs(A);
Assert(A = B);
end;
这是因为Abs(A)
返回一个浮点值,并且A=Abs(A)
实现为浮点比较
如果比较货币价值,我无法复制:
var
A: Currency;
begin
A:= 0.09;
Assert(A = Abs(A));
end;
var
A, B: Currency;
begin
A:= 0.09;
B:= Abs(A);
Assert(A = B);
end;
但是第二个示例也是一个潜在的错误,因为B:=Abs(a)
内部是一个浮点除法/乘法10000,取整为货币(int64),并且取决于FPU取整模式
我创建了一个,它被打开了。我刚刚发现Delphi XE2Abs函数不会使货币类型过载。 见 这些是abs支持的唯一类型
- 函数Abs(X:):实数;超载李>
- 函数Abs(X:):Int64;超载李>
- 函数Abs(X:):整数;超载李>
SameValue
。货币不是浮点type@valexhome根据文献记载,货币是固定的。至少在当前版本中:@Serg-Abs(Currency)可能是,编译器生成一个FCOMPP来将值与D2007进行比较。顺便说一句,我可以复制它。感谢您的及时回复,正如您所指出的,我使用了类似的解决方法来避免这个问题。尽管这个解释有道理,但这不被认为是Delphi IDE中的一个bug还是编译器本身的bug吗?@Khatchig-正式地说,这不是一个bug,而是一个记录在案的行为(“按设计”)。我同意这是一个不好的行为,Embarcadero可以修复它(使Abs(货币)
返回货币类型,而不是浮动货币)。