Getting The Decimal Part Of A Number In ColdFusion

Posted May 7, 2007 at 8:54 AM by Ben Nadel

Tags: ColdFusion

Over the weekend, I was fooling around with ColdFusion date/time values when I thought it would be useful to grab the decimal value of the date (the time part). Then it occurred to me - I don't think I have ever done this before. Now, I don't mean grabbing the actual fraction, I mean getting the integer value that is right of the decimal point.

After some good pacing, the only way to do this I could come up with through ColdFusion string manipulation. Since ColdFusion stores all simple values as strings, this makes manipulating values as strings quite natural. But, even when it came to string manipulation, I found two different ways to do this: one way uses a regular expression to strip out the decimal (and leading zero), the other way treats the value as a decimal-delimited list.

Here is the regular expression version:

  • <cffunction
  • name="GetDecimal"
  • access="public"
  • returntype="numeric"
  • output="false"
  • hint="Returns the decimal value of the given number (as an integer).">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Value"
  • type="numeric"
  • required="true"
  • />
  •  
  • <!---
  • Once we have the numeric decimal value, we can
  • convert it to a string so that we can use a regular
  • expression replace to strip out the starting zero
  • and decimal point.
  • --->
  • <cfreturn
  • ToString(
  • ARGUMENTS.Value - Fix( ARGUMENTS.Value )
  • ).ReplaceFirst(
  • "^0?\.",
  • ""
  • )
  • />
  • </cffunction>

In this version, I am getting the decimal value but subtracting the fix()'d value from the actual value. This should result in a zero-leading decimal value. Then, I convert it to a string (just in case) and strip out the leading zero and decimal point. This results in the integer form of the decimal:

  • <!--- Get decimal values values. --->
  • #GetDecimal( 134.5464 )#
  • #GetDecimal( 134 )#
  • #GetDecimal( 134.34464 )#
  • #GetDecimal( 134.45444554445 )#

... results in:

5464
0
34464
45444554445

Notice that the second value, 134, results in the decimal value, 0.

In this next version, we treat the value as a decimal-point-delimited list. By doing that, we can just grab the last list item to get the decimal value as an integer:

  • <cffunction
  • name="GetDecimal2"
  • access="public"
  • returntype="numeric"
  • output="false"
  • hint="Returns the decimal value of the given number (as an integer).">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Value"
  • type="numeric"
  • required="true"
  • />
  •  
  • <!---
  • To get the decimal value, we are going to treate the
  • value as a list with a decimal-point delimiter. When
  • doing this, we will append our own value to make sure
  • that the list has at least TWO (maybe three if there is
  • already a decimal place) list items.
  • --->
  • <cfreturn
  • ListGetAt( (ARGUMENTS.Value & ".0"), 2, "." )
  • />
  • </cffunction>

Ok, so now we have two different approaches, which do we use? Time for some speed tests. Now, I know that I get a lot of crap for running CFLoop speed tests (not true load bearing speed tests), but hey come on, I don't get enough sleep for that sort of thing :) Take it with a grain of salt if you like.

  • <!--- Test the ColdFusion regular expression method. --->
  • <cftimer
  • type="OUTLINE"
  • label="Partial Math Method And RegEx">
  •  
  • <cfloop
  • index="intI"
  • from="1"
  • to="1000"
  • step="1">
  •  
  • <!---
  • Get a random decimal value to make sure
  • that ColdFusion is not just optimizing
  • the compiled code.
  • --->
  • <cfset intDecimal = GetDecimal(
  • "1." &
  • RandRange( 1, 9 )
  • ) />
  •  
  • </cfloop>
  •  
  • </cftimer>
  •  
  •  
  • <!--- Test the decimal-delimited-list method. --->
  • <cftimer
  • type="OUTLINE"
  • label="Delimited List Method">
  •  
  • <cfloop
  • index="intI"
  • from="1"
  • to="1000"
  • step="1">
  •  
  • <!---
  • Get a random decimal value to make sure
  • that ColdFusion is not just optimizing
  • the compiled code.
  • --->
  • <cfset intDecimal = GetDecimal2(
  • "1." &
  • RandRange( 1, 9 )
  • ) />
  •  
  • </cfloop>
  •  
  • </cftimer>

Running the above speed tests, the delimited list method ran 2 to 3 times faster than the regular expression method (23-47ms vs. 74-123ms). Thinking about it, after the fact, this makes a lot of sense. The list method uses no math and no regular expressions; it just parses the number as a string and grabs part of its value. There is very easy to do. In the first version, I am actually doing math. No wonder it is slower.



Reader Comments

May 7, 2007 at 9:18 AM // reply »
5 Comments

I didn't do speed tests, but why not this?

<cfset number = 3.14159 />
<cfset decimal = number - int(number) />
<cfdump var="#decimal#">


May 7, 2007 at 9:38 AM // reply »
11,241 Comments

@Ryan,

That gives me:

0.14159

... what I wanted to get was just

14159

But this is basically doing the same thing as my Fix() method. Int() itself makes me a little nervous because it actually rounds, where as Fix() just strips off the decimal.


da
May 7, 2007 at 9:54 AM // reply »
1 Comments

hi try using listLast() a with "." as the delimiter.


May 7, 2007 at 9:56 AM // reply »
11,241 Comments

Good suggestion. ListGetAt(... 2), in this case is the same as ListLast()... but ListLast() is less typing :)


May 7, 2007 at 9:58 AM // reply »
11,241 Comments

Oh wait, no, it;s not the same thing (which is why I didn't use it). Think of this scenario:

4

I append ".0" to that to get:

4.0

ListGetAt(.. 2) in this case is the same as ListLast(). However, if my initial value is:

4.3

... and then I append ".0" to get:

4.3.0,

... then ListGetAt( ... 2) will give me "3", while ListLast() will get me "0".

I need to get ListGetAt() to deal with cases where I have a decimal point already vs. cases where I am dealing with a whole number.


May 7, 2007 at 10:48 AM // reply »
1 Comments

You may find this a little more straightforward:

#val(listRest(ARGUMENTS.Value, "."))#


May 7, 2007 at 10:51 AM // reply »
11,241 Comments

@Nelson,

Not a bad idea. Thanks.


Oct 23, 2007 at 2:02 PM // reply »
1 Comments

Why not use REVERSE(FIX(REVERSE(num)))?


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 7:52 AM
Nested Views, Routing, And Deep Linking With AngularJS
Hi, Just a quick thank you. As it happens, for my own purposes, the pending ui-router work being done in native angular is likely the one I'll adopt, but your exploration, code and documentation of ... read »
May 22, 2013 at 4:43 AM
How Do You Use The ColdFusion CFParam Tag?
'<cfparam>' or 'isDefined()and <cfset>' performs the same task.Is there any difference? ... read »
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools