Why 1.99 suddenly no longer equals 1.99

A strange problem suddenly occurs in all my Delphi 7 and Delphi 2009 unit tests.

I used DUnit CheckEquals to compare two Currency values, like

  CheckEquals(1.99, SomeCurrencyValue)

This worked fine in the IDE and in our build scripts, which run using the same version of DUnit for two years. Now, all of a sudden, all tests fail with strange error messages like

Expected: <1.99> - Found: <1.99>

With some newsgroup help I found that something has changed a processor flag which is responsible for floating point operations. Digging deeper in my unit tests, I found the root cause in the IBX component TIBDatabase, which seems to modify this flag.

TIBDataBase.Create(nil) changes the value of Get8087CW from $1372 to $1272, a very strange value.

procedure TForm2.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(Format('FPU CW = $%4.4X',[Get8087CW]));
  TIBDataBase.Create(nil);
  Memo1.Lines.Add(Format('FPU CW = $%4.4X',[Get8087CW]));
end;

Tested on two systems running Windows 2000 SP 4, InterBase 7.5.1 and 2007 libraries (gds32.dll), Delphi 7 and Delphi 2009

Advertisements

3 thoughts on “Why 1.99 suddenly no longer equals 1.99

  1. I did some more checks with Delphi 2007 and InterBase 2007: the failure does not occur.

    But: if I manually call Set8087CW with the values you mention, I can reproduce.

    The difference between $1372 (default) and $1272 (failure) is the internal mantissa precision. It changes from 64 bits to 53 bits, which is enough to make 1.99 not equal to 1.99.

    I have seen behaviour like this in the past with some networking stacks in the Turbo Pascal 7 era, with some C++ DLL’s in the Delphi 1-3 era, and some printer drivers in the Delphi 5-7 era.

    What kind of system are you using? (Processor, OS, 32-bit/64-bit, drivers, etc)?

    –jeroen

  2. Pingback: Delphi - Michael Justin had strange floating point results when his 8087 FPU Control Word got hosed « The Wiert Corner

  3. Thank you!! I’ve been sitting here trying to figure out what is causing my checkEquals on currencies to fail on the second pass, but not the first. Something in some setup in a further down unit test is modifying the mantissa from $137F to $127F. I don’t have any calls in my code base to set8087CW/get8087CW, but I’m now persisting it between setup and then setting the previous value back on teardown. Thank you for posting this back in 2009.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s