将 DUnit CheckEquals 中的问题与货币字段值进行比较

发布于 2024-07-13 01:21:49 字数 445 浏览 5 评论 0原文

我正在比较 DUnit 中的一些货币值,但它在我的机器上根本不起作用(在其他机器上起作用,但在我的机器上不起作用)。

示例:

CheckEquals(16.65, SomeCurrencyFieldValue);

Raises:

expected: <16,65> but was: <16,65>

如果执行以下操作,则比较有效:

var
  Temp: Currency;
begin
  Temp := 16.65;
  CheckEquals(Temp, SomeCurrencyFieldValue);

问题是:为什么当我将值直接传递给 CheckEquals 方法时比较不起作用?

I'm comparing some currency values in DUnit but it is not working at all on my machine (work on others, but not on mine).

An example:

CheckEquals(16.65, SomeCurrencyFieldValue);

Raises:

expected: <16,65> but was: <16,65>

if do the following the comparison then works:

var
  Temp: Currency;
begin
  Temp := 16.65;
  CheckEquals(Temp, SomeCurrencyFieldValue);

The question is: Why the comparison doesn't work when I pass the value direct to the CheckEquals method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

清醇 2024-07-20 01:21:49

该问题与运行时的货币值如何转换为扩展值以及浮点文字如何在运行时转换为扩展值有关。编译时间。 如果两种情况下的转换不同,则传递给 CheckEquals 的值可能不相等。

值得在调试器的 CPU 窗口中检查其中任何一个值在为函数调用做准备的过程中是否经过中间 Double 值到 Extended 。 额外的转换会影响结果的确切值。

另一件需要考虑的事情是,16.65 不能精确地表示为扩展值,但它可以精确地表示为货币值。 尽管 Currency 被归类为浮点类型,但它实际上是定点缩放的 64 位整数。 这可能是在考虑到这一点的 DUnit 中请求额外的 CheckEquals 重载的理由。

The issue has to do with how Currency values get converted to Extended values at run time versus how floating-point literals get converted to Extended values at compile time. If the conversion isn't the same in both cases, then the values passed to CheckEquals may not compare equal.

It would be worth checking in the debugger's CPU window whether either of the values goes through an intermediate Double value on its way to Extended in preparation for the function call. An extra conversion would affect the exact value of the result.

Another thing to consider is that 16.65 is not representable exactly as an Extended value, but it is representable exactly as a Currency value. Although Currency is classified as a floating-point type, it is really a fixed-point scaled 64-bit integer. That's probably grounds for requesting an additional CheckEquals overload in DUnit that takes that into account.

月朦胧 2024-07-20 01:21:49

我看到 Delphi 2007 dUnit 源代码中只有 CheckEquals() 用于扩展值。 但您可以使用这个:

procedure CheckEquals(expected, actual: extended; delta: extended;
  msg: string = ''); overload; virtual;

并为货币价值提供适当的增量。

I see that there is only CheckEquals() for extended values in the Delphi 2007 dUnit sources. But you could use this one:

procedure CheckEquals(expected, actual: extended; delta: extended;
  msg: string = ''); overload; virtual;

and give a proper delta for currency values.

私野 2024-07-20 01:21:49

我遇到了同样的问题。 看起来有些 DLL 会修改 FPU(处理器)控制字。 这解释了为什么错误并不总是发生。 当添加一些使用先前测试套件以外的单元的新测试时,它可能会突然出现。 或者软件更新安装了错误的 DLL。 我在我的博客上写过:

我还发现Delphi包含一个SafeLoadLibrary函数,它可以恢复控制字。

这也解释了为什么原来的问题提到问题是机器相关的。

I encountered the very same problem. It looks like some DLLs modify a FPU (processor) control word. This explains why the error does not occur always. It can appear suddenly when some new tests, which use other units than the previous test suite, are added. Or if a software update installs bad DLLs. I have written about on my blog:

I also found that Delphi contains a SafeLoadLibrary function, which restores the control word.

This also explains why the original question mentions that the problem is machine-dependent.

这样的小城市 2024-07-20 01:21:49

这是一个建议的解决方案:

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');

here is a suggested solution:

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;

I know its bad implementation, but just an idea, that i like better then "delta", and much easier to use.

In the current version of dunit you can use

procedure CheckEquals(expected, actual: extended; delta: extended; msg: string = ''); overload; virtual;
CheckEquals(0.011,0.01,0.009,'will pass');
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文