So there was an incident that happened a while ago in my company regarding to math number rounding issue.

We are using Salesforce to run the performance report where the sales performance is indicated by multiple criteria such as sales amount, customer count and etc. Because of the math number rounding issue, the final result generated from the report was not acceptable by sales person.

Today, we are going to do some quick exercises to begin with setScale() method on Decimal class.

Say we have a number of 5.234, we want to round it to 2 decimals only, what would it be?

Decimal num = 5.234;
num = num.setScale(2);
System.assertEquals(num, 5.23);

That's perfectly fine. We round down because the last digit is 4 which is less than 5 (half).

What about 5.236?

Decimal num = 5.236;
num = num.setScale(2);
System.assertEquals(num, 5.24);

Well, the number rounds up since 6 is greater than 5 which is exactly what we thought.

Let's move on to next one, 5.235. What about it?

Decimal num = 5.235;
num = num.setScale(2);
System.assertEquals(num, 5.24);

The assertion is still correct though. Let's think of it as 5 is also part of the rounding up list along with 6,7,8 and 9. If we think so, the assertion is correct.

What about 5.245? Will it round to 5.25? Let's see!

Decimal num = 5.245;
num = num.setScale(2);
System.assertEquals(num, 5.25); // Assertion Failedd: Expected: 5.24, Actual: 5.25

What is happening? Why is it round down instead of rounding up like 5.235?

Let's look at the documentation and find out what the black magic is behind the scene.

Decimal Class in Salesforce:https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_decimal.htm

So before we get into any class methods, you can find a big section explaining different types of Rounding Mode. Here, we are only going to focus on mode HALF_EVEN, because it is the default rounding mode for setScale() method.

The explanation of HALF_EVEN is shown as below:

Rounds towards the “nearest neighbor” unless both neighbors are equidistant, in which case, this mode rounds towards the even neighbor. This rounding mode behaves the same as the HALF_UP rounding mode if the digit to the left of the discarded fraction (decimal point) is odd. It behaves the same as the HALF_DOWN rounding method if it is even.

For example,

NumbersetScale(2)
5.2055.20
5.2155.22
5.2255.22
5.2355.24
5.2455.24
5.2555.26
5.2655.26
5.2755.28
5.2855.28
5.2955.30

Is that something mind-blown to you😝? Well, I just know about that recently. This rounding issue has never come across my mind before. When I was in school, teachers always taught us that rounding digit 5 should always round up no matter what. If you want to always round up when the discarded fraction (decimal point) is >= 5, you can set the additional parameter like this: setScale(2, System.RoundingMode.HALF_UP). That way, it will ensure rounding up is applied.

One thing you must bear in mind is that if the number has more decimal points behind our desired decimal places, the result will always round up. For example, from the table above, 5.245 is rounded to 5.24 but 5.2451 will be rounded to 5.25.


Well, that's all about it! I hope you can get something out from it as well! See you next time!

Post was published on , last updated on .

Like the content? Support the author by paypal.me!