Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid rounding problems when comparing currency values in Delphi?

AFAIK, Currency type in Delphi Win32 depends on the processor floating point precision. Because of this I'm having rounding problems when comparing two Currency values, returning different results depending on the machine.

For now I'm using the SameValue function passing a Epsilon parameter = 0.009, because I only need 2 decimal digits precision.

Is there any better way to avoid this problem?

like image 272
Erick Sasse Avatar asked Nov 27 '22 19:11

Erick Sasse


1 Answers

The Currency type in Delphi is a 64-bit integer scaled by 1/10,000; in other words, its smallest increment is equivalent to 0.0001. It is not susceptible to precision issues in the same way that floating point code is.

However, if you are multiplying your Currency numbers by floating-point types, or dividing your Currency values, the rounding does need to be worked out one way or the other. The FPU controls this mechanism (it's called the "control word"). The Math unit contains some procedures which control this mechanism: SetRoundMode in particular. You can see the effects in this program:

{$APPTYPE CONSOLE}

uses Math;

var
  x: Currency;
  y: Currency;
begin
  SetRoundMode(rmTruncate);
  x := 1;
  x := x / 6;
  SetRoundMode(rmNearest);
  y := 1;
  y := y / 6;
  Writeln(x = y); // false
  Writeln(x - y); // 0.0001; i.e. 0.1666 vs 0.1667
end.

It is possible that a third-party library you are using is setting the control word to a different value. You may want to set the control word (i.e. rounding mode) explicitly at the starting point of your important calculations.

Also, if your calculations ever transfer into plain floating point and then back into Currency, all bets are off - too hard to audit. Make sure all your calculations are in Currency.

like image 115
Barry Kelly Avatar answered Dec 11 '22 00:12

Barry Kelly