3

I am developing a financial system and want to have a defined policy for rounding monetary values.

Given the following layers:

  • View
  • API
  • Entity Model
  • Persistence

If I am passing a monetary value through these layers, and maybe using it in calculations in the model, at what layer (if any) should I be applying my "default" rounding policy?

My instinct is in the View, as rounding the number is a "view" concern, like formatting a date. I also feel it could cause problems if my entities round money values as this could affect the accuracy of calculations. However if my API specifies a value as "money" it would seem incorrect to provide consumers with values that are not rounded e.g. £109.563393939939 rather than £109.56.

I have been unable to find any "best practice" around this.

Aside from this old question: https://stackoverflow.com/a/3840903/470183

4
  • 9
    Typically, financial systems do not round at all, but represent all monetary amounts as integral types, e.g. Number of Cents in an account. Jan 16, 2019 at 13:25
  • 2
    Any policy you have should be driven by the requirements for your system. If the requirements don't say round, don't round.
    – Blrfl
    Jan 16, 2019 at 13:35
  • 1
    @KillianFoth, financial softwares will have to round, fairly often, regardless how amounts of stored. E.g. you can't sensibly compute interests without several decimals places beyond your smallest unit. Jan 16, 2019 at 14:35
  • 1
    It should go with the rest of the business rules layer...Where is that?
    – NoChance
    Jan 16, 2019 at 14:41

5 Answers 5

12

Monetary values in general do not use floating point (always approximation errors!), but fixed point, as BigDecimal in java, DECIMAL in SQL. For currencies you then have a defined precision (2 decimals for instance).

Now national regulations prescribe the precision of some calculations, like taxes with a precision of 6 (Europe). These kind of precisions should be part of the business logic, giving rounded exact values of calculations.

Higher layers like for the views are then given a fixed precision, with already rounded values from calculations.

In this way end-point summing (outside the system, say in exported Excel) of exported values will give no deviations from in-system sums.

10

There are two levels of rounding you should be doing. The primary one is in the business logic to round to the level of precision required. The UI can round for display purposes independently. Rules around this should be part of your requirements, some of them are also likely derived from laws that may specify precision of various transactions or how to round in different situations.

1

 I also feel it could cause problems if my entities round money values as this could affect the accuracy of calculations. However if my API specifies a value as "money" it would seem incorrect to provide consumers with values that are not rounded e.g. £109.563393939939 rather than £109.56.

This is correct.

If you're building a financial application, I don't see why you would want to lose accuracy when you store data. No rounding should occur on its way in (although controlling decimal places entered by the user isn't a bad idea).

That being said, if you're working with the GBP currency (or any similarly formatted currency), then users won't want to see more than 2 decimal places. For this reason I would ensure only the view layer rounds the data, and I would follow the conventional "half up" rounding.

1
  • 2
    If the view layer does the rounding, you can get unexpected results that differ from what other financial institutions compute. A complex procedure can yield different final values depending on what step the rounding takes place. Rounding is a business/policy decision. Jan 16, 2019 at 14:38
1

When you do any calculations, find the exact rules for that calculation. For example the tax rules governing the calculation of VAT in the U.K. are let’s say”interesting”.

The calculations often include one or more rounding steps. There may be rounding steps not mentioned in your specs, but required - in that case you have someone update the specs. It is unlikely that there are useful “default” rules.

So you perform every calculation according to its rules and then don’t change it. If the result is £105.3743275 according to the rules of the calculation then that is how you store it. If a rounding step was required at the end as part of the calculation, you perform it and save the rounded value.

0

Other answers noted thank you, I am proposing this general policy:

  • View - Apply a single default rounding policy for display
  • API - No rounding
  • Model - No rounding except when specified in business requirements
  • Persistence - Decide the required precision and scale needed for storage and apply single default rounding policy on storing data

In summary 3 of the layers may need to round!

For my specific situation with monetary amounts: GBP system, SQL Server, .NET, EntityFramework, Open API (Swagger) REST JSON service and web client

  • By default money is stored Decimal 18, 2 in the database, unless the business requirement states we need more dps.
  • ROUND all monetary values on storing data using Midpoint Rounding towards Zero
  • NO rounding in the model unless specifically defined by a business requirement (e.g. 6 dps for tax calculations)
  • NO rounding in the facade or the API layer - hence API could return a "monetary" value as £158.992323232
  • ROUND all money values for display to 2 dps using Midpoint Rounding towards Zero
1
  • You should tell Apple that JSON doesn't have decimal numbers. They will be surprised.
    – gnasher729
    Jan 23, 2019 at 1:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.