Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Delphi round Currency during multiplication

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?

like image 332
Chet Avatar asked Feb 07 '23 00:02

Chet


1 Answers

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.

like image 126
LU RD Avatar answered Feb 16 '23 19:02

LU RD