Is there a way to maintain the scale of a Decimal across multiple operations?

I thought setScale appears to be a normal set method on the Decimal class. Meaning that you can set the scale, and then future operations saved in that object will be rounded from there out. Instead, setScale seems like a method to one time return the scaled value, and is not maintained. Is this the intended behavior?

Does this mean that for every operation throughout our code, we need to round before we save the value back in the decimal? That seems error prone, and could cause rounding problems in large sets of classes.

  • Welcome to SFSE! Is there any code you can share - it would help others understand what you have already tried. – Kelly J Andrews Dec 3 '14 at 20:24

No there isn't a way to set the scale once and have it apply across multiple operations. So you need explicit calls in your code. That means using the Decimal.setScale method and also the Decimal.divide method in many places. Typically some intermediate calculations will require many decimal places to be preserved but in other places business requirements will require e.g. 2 decimal places and a particular rounding algorithm. So define some constants so at least the values are named in a meaningful way.

A further matter is that if your don't set the scale before storing a value the value can be stored at a larger scale than the value is presented in the UI i.e. the scale you define for a numeric field is applied at presentation time not when a value is stored. This can introduce errors into later calculations or in data exported to other systems. So make sure you explicitly set the scale on values that are persisted.

If you are doing financial calculations typically you do need to be precise about rounding and so will end up with some blocks of code looking like this:

Decimal factor = net.divide(up.Net__c, INTERMEDIATE_SCALE, ROUNDING_MODE);
p.NetBeforeTaxes__c = (up.NetBeforeTaxes__c * factor).setScale(SCALE, ROUNDING_MODE);
p.NetAfterTaxes__c = (up.NetAfterTaxes__c * factor).setScale(SCALE, ROUNDING_MODE);

Its better to think about - and write tests for - rounding up front than be trying to track down 1 cent rounding errors a year later when you are in production.

| improve this answer | |
  • Thanks, this is exactly what I suspected and wanted to be sure about. Thanks for the detailed explanation. – adm Dec 4 '14 at 15:28

It doesn't work the way you think. That method goes on a specific Decimal object. It's not a static Decimal method. There isn't a way to round all Decimals in your org.

| improve this answer | |
  • It is not that I want a static method to work on all Decimals, but rather for the specific decimal object I declare and call setScale on. After calling setScale on an instance of Decimal, i want that Decimal to maintain its scale after subsequent operations. Unfortunately, I dont think it works that way either... – adm Dec 3 '14 at 20:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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