Custom rounding in ColdFusion

This post is more than 2 years old.

Yesterday a friend asked an interesting question. Normal rounding is based on the rule we are familiar with. Anything decimal point that is 5 and higher will round up to the next number. So 11.5 becomes 12. My friend though had a client who wanted to change the rules. Instead of rounding on 5, they wanted to round on 4. So 11.4 would become 12. 11.39 would round down to 11. Sounded weird to me, but maybe that's what the Wall Street folks have been doing lately.

I whipped up a quick function that treated numbers like strings:

function myRound2(x) { if(listLen(x,".") is 1) return x; if(left(listLast(x, "."),1) >= 4) return incrementValue(listFirst(x,".")); return listFirst(x,"."); }

This worked fine until he tested with a negative number. He came back with a nicer solution (makes me wonder if he will ever ask me again for help!) that worked in all cases:

function myRound(x) { if (abs(x - int(x)) >= .40) return ceiling(x); else return int(x); }

His solution correctly handled the negative numbers. You could even make it a bit more abstract:

function myRound(x,y) { if (abs(x - int(x)) >= (y/10)) return ceiling(x); else return int(x); }

This will let me pass any value for the rounding limit.

Anyway, I'll use the above as a good springboard to remind folks about unit testing. When he found the issue with my code and negative numbers, it would have been the perfect place to write a unit test to ensure that never became a problem again.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA

Archived Comments

Comment 1 by Scott P posted on 9/30/2008 at 8:04 PM

nice - "Sounded weird to me, but maybe that's what the Wall Street folks have been doing lately"

Comment 2 by Edgar Soto posted on 9/30/2008 at 11:42 PM

Agreed. A little weird.

Comment 3 by Tim posted on 10/1/2008 at 12:09 AM

Your friends needs to make sure he gets paid before this fishy business rule brings down their business. :)

Comment 4 by Troy L Allen Sr posted on 10/1/2008 at 5:31 PM

I was just discussing CF's lack of a good "Round To X Decimal Places" function. We had run into the classic "internal FPU rounding error", but we were dealing with Money so we needed it properly rounded to 2 decimal places. We ended up doing "myMoney = ROUND(myMoney*100)/100", but of course that seems kind of kludgy. There are several ways of getting to Integers (Round(), Int(), Fix(), Ceiling(), etc), but none that deal with precision of a decimal place. And unfortunately both NumberFormat() and DollarFormat() simply truncate off any characters past the mask with no rounding.

Comment 5 by Alan McCollough posted on 10/1/2008 at 8:35 PM

Well, he could Nutritional Information rounding; .999999 calories = 0 CALORIES! 1.99999 servings in a container = 1 Serving!

Comment 6 by Alan McCollough posted on 10/1/2008 at 8:42 PM

Actually, I just remembered an interesting rounding issue I ran into last week. I have a calendaring app here, and modified it so that users can upload events using an Excel file as a template. I'm using Ben Nadel's POI cfc to work with the Excel files (works awesome). Thing is, a date/time field in Excel, after being mangled through POI into a query, returns a floating-point numeric representation of the date, using "time begins in 1900-01-01" format.

Now the weird thing is, rounding definately messes up the time! If somebody has a date/time in Excel of "2009/04/01 4:00 pm", it'll translate in CF as "2009/04/01 3:59:59 pm". I slapped together a UDF and submitted it to to correct for this quirk of rounding when handling date/times.

So yeah, rounding (and floating-point arithmetic in general) is not without it's quirks.

Comment 7 by Jim Ruzicka posted on 10/3/2008 at 12:16 AM

That is a bit strange, i have dealt with rounding where if there is any remaining decimals always round up, in which case I also had to look at the number as a string and did something very similar.

Comment 8 by Hussein posted on 10/3/2008 at 11:20 PM

I've never heard of anyone rounding numbers like that before. Weird indeed.

Comment 9 by Armando posted on 1/16/2010 at 12:55 AM

Thanks a lot, about the comment above its nor weird at all, specially talking about wight units and shippings, for example UPS consider 1.1 still like 1 Kilo and 1.2 like 2 Kilos.


Comment 10 by Randy L. Smith posted on 1/30/2014 at 10:55 AM

Thanks, Ray!

That gave me the mindset I needed to figure out how to round up to the next 10. I am writing a little conversion from Access 2010 to SQL Server 2012 and needed to make sure the new varchar columns would be big enough for the copied-in data.

Once I get "y" (length of longest string in the field), I can get the next higher column size in increments of 10 via #ceiling(y/10)*10#