What is your advice on:
- compensation of accumulated error in bulk math operations on collections of Money objects. How is this implemented in your production code for your locale?
- theory behind rounding in accountancy.
- any lite开发者_开发问答rature on topic.
I currently read Fowler. He mentions Money type, it's typcal structure (int, long, BigDecimal), but says nothing on strategies.
Older posts on money-rounding (here, and here) do not provide a details and formality I need.
Thoughts I found in the inet relate to "Round half even" as the best way to balance error.
Thanks for help.
There are many rounding issues when recording financial data. First issue is ability to store and retrieve exact decimal numbers
- most databases offer decimal data type on which you can specify the number of digits before and after decimal point (currencies vary in number of decimal digits, too, I've dealt with currencies with 0, 2, 3 decimal digits)
- when dealing with this data and you want to avoid any unexpected rounding errors on the application side you can use BCD as generic approach, or you can use integers to represent any fixed decimal notation or mix your own
If this first issue is sorted out then no addition (or substraction) can introduce any rounding errors. Same goes for multiplication by integer.
The second issue, after you are able to store and retrieve data without loss of information, are expected rounding errors due to division (or multiplication by non integer).
For example if your currency format allows 2 decimals and you want to store transaction that records balances a debit of 10 to 3 equal pieces you can only store it like
10.00
-3.33
-3.33
-3.33
and
-0.01
(rounding error)
This is expected problem that will occur regardless of the data type storage choice and that needs to be taken care of if you want your accounts to balance. This situation is mainly introduced by division (or by multiplication by non integers that have many significant digits).
One way to deal with this is to verify if your data balances after such operations and recognize the allowed rounding difference as opposed to an error situation.
EDIT: As for references to literature, this one seems interesting and not too long and concerns quite wide audience with interesting scenarios.
Use Banker's rounding. You round to the nearest two-penny.
http://www.xbeat.net/vbspeed/i_BankersRounding.htm
You can expand upon this to round toward
the nearest two-penny instead. So 22.5 rounds to 22, but 23.5 rounds to 24. 23.1 and 22.9 both round to 23. However, the original banker's algorithm is more popular.
Never store money values in a double or float - use an int
or long
as there is no way to store 0.1 accurately in binary.
It all depends on the application. Hopefully there aren't too many situations where rounding is required. For example, transferring money from one account to another requires no rounding.
For situations where rounding is required, it doesn't really matter what you do as long as you pick a policy, communicate it, and stick to it. For instance, I believe the interest on my savings account rounds down to the nearest penny.
What you should do may well be informed by the conventions of the market or jurisdiction you are operating in. For example, pricing bonds in the Australian market requires that you round certain intermediate operations to 8 decimal places. The final price is quoted to a specific number of decimals (3 I think off the top of my head).
If you are dealing with an accounting app, I would expect the relevant accounting standards for your legal environment to possibly dictate this.
I've worked a bit (just a bit) with monetary amounts and I was extremely curious as to the strategy used in my company...
It turns out that we use double
, but they've thought about it.
The thing is that the amounts we deal with are not that great (say less than 10k) and at most we need 3 digits after the decimal, for a total of 7 significant digits.
Since we are using 64bits software (and C++) the double
type offers enough significant digits for the number of operations we carry on it :)
If you need more precision, there are algorithms to use (for example while adding multiple moneys) but personally I think the heart of the issue comes more from:
- conversion from one money to another, which keeps changing of course
- printing issues, with some moneys requiring no decimal, others requiring 2 at most, etc...
Perhaps could you expand on the operations you're doing ?
精彩评论