Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

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.

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');
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top