我正在比较DUnit中的一些货币值,但它在我的机器上根本不起作用(在其他机器上工作,但在我的机器上不工作)。
一个例子:
CheckEquals(16.65, SomeCurrencyFieldValue);
引发:
expected: <16,65> but was: <16,65>
如果进行以下比较,则可以起作用:
var
Temp: Currency;
begin
Temp := 16.65;
CheckEquals(Temp, SomeCurrencyFieldValue);
问题是:当我将值直接传递给CheckEquals方法时,为什么比较不起作用?
答案 0 :(得分:5)
该问题与Currency
值在运行时如何转换为Extended
值以及浮点文字在编译时如何转换为Extended
值有关。如果在两种情况下转换都不相同,那么传递给CheckEquals
的值可能无法相等。
值得在调试器的CPU窗口中检查在准备函数调用时,其中任何一个值是否在到Double
的路上经过中间Extended
值。额外的转换会影响结果的确切值。
要考虑的另一件事是16.65不能完全表示为Extended
值,但 可以完全表示为Currency
值。虽然Currency
被归类为浮点类型,但它实际上是一个定点缩放的64位整数。这可能是请求在DUnit中额外CheckEquals
重载的理由,并将其考虑在内。
答案 1 :(得分:1)
我发现在Delphi 2007 dUnit源代码中只有CheckEquals()用于扩展值。但你可以用这个:
procedure CheckEquals(expected, actual: extended; delta: extended;
msg: string = ''); overload; virtual;
并为货币值提供适当的增量。
答案 2 :(得分:1)
我遇到了同样的问题。看起来有些DLL会修改FPU(处理器)控制字。这解释了为什么不总是发生错误。当添加一些使用除先前测试套件之外的其他单元的新测试时,它可能突然出现。或者,如果软件更新安装了错误的DLL。我在我的博客上写过:
我还发现Delphi包含一个SafeLoadLibrary函数,用于恢复控制字。
这也解释了为什么原始问题提到问题与机器有关。
答案 3 :(得分:-1)
这是一个建议的解决方案:
procedure CheckEquals(expected, actual: double; Precision:integer; msg:string ='');overload;virtual;
...
procedure TAbstractTest.CheckEquals(expected, actual: double;
Precision: integer; msg: string);
var
I: Integer;
begin
FCheckCalled := true;
for I := 0 to Precision do begin
Expected := Expected * 10;
Actual := Actual * 10;
end;
if Round(Expected) <> Round(Actual) then
FailNotEquals( IntToStr(Round(Expected)), IntToStr(Round(Actual)), msg, CallerAddr);
end;
我知道它的实现不好,但只是一个想法,我更喜欢“delta”,更容易使用。
在当前版本的dunit中,您可以使用
procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');