rate : Currency;
mod1 : Currency;
mod2 : Currency;
mod_rate : Currency;
rate := 29.90;
mod1 := 0.95;
mod2 := 1.39;
mod_rate := rate * mod1 * mod2;
If you perform this calculation on a calculator you get a value of 39.45295
. Since Delphi's Currency
datatype is only precise to 4 decimals it internally rounds the value. My testing indicates that it uses Banker's rounding so that mod_rate should contain a value of 39.4530
, however in this particular case it truncates to 39.4529
.
I have 40,000 of these calculations and all are correct except the above. Here is an example that rounds up:
rate := 32.25;
mod1 := 0.90;
mod2 := 1.15;
This equals 33.37875
on a calculator and according to Banker's rounding would go to 33.3788
, which is what Delphi does.
Could someone shed some light as to what Delphi is doing here?
Currency
calculations takes place in the fpu with extended precision, even though the currency itself is a 64 bit integer value.
The problem you have is with floating point binary representation, rather than rounding errors. You can see the floating point representation of 39.45295 here: What is the exact value of a floating-point variable?
39.45295 = + 39.45294 99999 99999 99845 67899 95771 03240 88111 51981 35375 97656 25
The extended precision value is below 39.45295, hence the rounding downwards.
Use a decimal arithmetic library instead to avoid these kind of errors.
To see that the floating point arithmetic is performed in the fpu for currency
calculations, here is a disassembly:
mod_rate := rate * mod1 * mod2;
0041D566 DF2D20584200 fild qword ptr [$00425820]
0041D56C DF2D28584200 fild qword ptr [$00425828]
0041D572 DEC9 fmulp st(1)
0041D574 DF2D30584200 fild qword ptr [$00425830]
0041D57A DEC9 fmulp st(1)
0041D57C D835C4D54100 fdiv dword ptr [$0041d5c4]
0041D582 DF3D38584200 fistp qword ptr [$00425838]
0041D588 9B wait
fmulp
and fdiv
are done with extended precision.
If integer operations had been used, the instructions would have been fimul
and fidiv
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With