Using ColdFusion's PrecisionEvaluate() Function To Perform Big Integer Math

Posted October 27, 2010 at 9:56 AM by Ben Nadel

Tags: ColdFusion

Did you know that ColdFusion has a function named PrecisionEvaluate()? Neither did I. I randomly came across it the other day when I was looking up information about ColdFusion's integer division operator. PrecisionEvaluate() works exactly like the Evaluate() function except for that it uses BigInteger objects when performing mathematical operations.

Before we look at how the precisionEvaluate() function works, let's take a look at the normal behavior of big integer math in ColdFusion:

  • <!---
  • Create two numbers that are too large to be signed integers in
  • ColdFusion. These are strings now, so shouldn't pose a problem
  • until we try to do math with them.
  • --->
  • <cfset hugeNumberA = repeatString( "1", 32 ) />
  • <cfset hugeNumberB = repeatString( "2", 32 ) />
  •  
  • <!--- Perform huge integer math! Mwaa ha ha ha ha! --->
  • <cfoutput>
  •  
  • Number A: #hugeNumberA#<br />
  • Number B: #hugeNumberB#<br />
  •  
  • Sum: #(hugeNumberA + hugeNumberB)#<br />
  • Product: #(hugeNumberA * hugeNumberB)#
  •  
  • </cfoutput>

As you can see, I'm using signed integers larger than 31 bits (the largest integer that ColdFusion can properly model with precision). When we run the above code, forcing the huge number "strings" to become "numbers", we get the following output:

Number A: 11111111111111111111111111111111
Number B: 22222222222222222222222222222222

Sum: 3.33333333333E+031
Product: 2.46913580247E+062

As you can see, the mathematical outcomes of the large number operations can only be held to a loose precision.

Now, let's do the same exact thing; however, this time, we are going to perform the mathematical operations in the context of the precisionEvaluate() function:

  • <!---
  • Create two numbers that are too large to be signed integers in
  • ColdFusion. These are strings now, so shouldn't pose a problem
  • until we try to do math with them.
  • --->
  • <cfset hugeNumberA = repeatString( "1", 32 ) />
  • <cfset hugeNumberB = repeatString( "2", 32 ) />
  •  
  • <!---
  • This time, we are going to perform math on the two numbers using
  • precisionEvaluate() which uses BigInteger objects to perform the
  • mathetmatical operations.
  • --->
  • <cfoutput>
  •  
  • Number A: #hugeNumberA#<br />
  • Number B: #hugeNumberB#<br />
  •  
  • Sum: #precisionEvaluate( hugeNumberA + hugeNumberB )#<br />
  • Product: #precisionEvaluate( hugeNumberA * hugeNumberB )#
  •  
  • </cfoutput>

As you can see, all we've done is wrapped our mathematical operations in a call to the precisionEvaluate() function. When we run this code, we get the following output:

Number A: 11111111111111111111111111111111
Number B: 22222222222222222222222222222222

Sum: 33333333333333333333333333333333
Product: 246913580246913580.......5308641975308641975308642

NOTE: I have removed a few digits to prevent wrapping on the blog.

This time, both the sum and product operations were able to preserve full precision.

One thing you might notice in the above code is that the statement we passed to the precisionEvaluate() function is not quoted. The documentation on this function states that if you're just performing arithmetic expressions, using non-quoted values will result in faster execution. I have to assume that this is a compile-time optimization since one would think that performing the math first would negate the use of precisionEvaluate().

After the precisionEvaluate() function executes, it returns a big decimal value that represents the result of the last expression evaluated (remember, the evaluate() functions can execute multiple statements). This result can then be used to perform further large number arithmetic; or, it can be used in standard math and will be converted back to a normal numeric value automatically.

To get a sense of what actually comes back from precisionEvaluate(), let's loop over the methods that are available on the resultant object:

  • <!--- Get the big integer result. --->
  • <cfset bigResult = precisionEvaluate( 3 * 3 ) />
  •  
  • <!--- Get the methods available on this result. --->
  • <cfset methods = bigResult.getClass().getMethods() />
  •  
  • <cfoutput>
  •  
  • <!--- Output the result's class type. --->
  • Class: #bigResult.getClass().getName()#<br />
  • <br />
  •  
  • <!--- Loop over each method to output it's name. --->
  • <cfloop
  • index="method"
  • array="#methods#">
  •  
  • #method.getName()#<br />
  •  
  • </cfloop>
  •  
  • </cfoutput>

This time, we are executing really simple math; however, our precisionEvaluate() method will use BigInteger values regardless. After performing the big integer math, we are outputting the resultant class type and its methods (NOTE: I have removed some duplicate method names):

Class: java.math.BigDecimal

add
equals
toString
hashCode
abs
pow
min
max
compareTo
valueOf
intValue
longValue
floatValue
doubleValue
signum
round
ulp
scale
subtract
multiply
divide
divideAndRemainder
remainder
negate
toBigInteger
scaleByPowerOfTen
unscaledValue
precision
divideToIntegralValue
plus
setScale
movePointLeft
movePointRight
stripTrailingZeros
toEngineeringString
toPlainString
toBigIntegerExact
longValueExact
intValueExact
shortValueExact
byteValueExact
byteValue
shortValue

As you can see, the result is a BigDecimal instance and provides all of the native BigDecimal methods.

Of course, you don't have to use the result as if it were a special class; you can simply use the result in further math and ColdFusion will convert it back to a native numeric value:

  • #(precisionEvaluate( 3 * 3 ) + 1)#

... which gives us the expected:

10

The BigInteger class has a lot of useful functionality; but, it's nice to know that ColdFusion provides a way to perform large number mathematical operations without having to dip into the Java layer. Now that I know this function is here, I am sure I will be able to find a good use for it.




Reader Comments

Oct 27, 2010 at 10:15 AM // reply »
70 Comments

Wow. This looks to be the EASIEST way to do BigIntegers. Thanks!


Oct 27, 2010 at 10:15 AM // reply »
2 Comments

What an interesting find. ColdFusion was difficult for me when I was first starting to learn it, and anything math makes me uncomfortable, so I read this post expecting to be made exceptionally uncomfortable (but I've learned, the only way you learn is to let yourself sit in those uncomfortable feelings). Instead, I found it super interesting and oddly comfortable. Will I ever do anything that needs it? Maybe not, but I know I could if I needed to, now. Who knew CF (and especially math) could do that :)


Oct 27, 2010 at 10:21 AM // reply »
11,238 Comments

@WebManWalking,

Yeah, this is super easy. I could also see myself very easily becoming lazy about creating BigInteger instances :) For example, it's way easier to do this:

  • <cfset x = precisionEvaluate( 1 ) />

... than it is to do this:

  • <cfset x = createObject( "java", "java.math.BigInteger" ).init(
  • javaCast( "string", 1 )
  • ) />

Of course the result of precisionEvaluate() is a BigDecimal, not a BigInteger; but still, you know what I'm saying.

@JJ,

I am super flattered that I was able to write about this in a way that allowed you to keep your cool :) That's exactly the kind of feeling that I want to create with my explorations.


Oct 27, 2010 at 12:28 PM // reply »
40 Comments

did i know about PrecisionEvaluate()? why yes i did ;-)

http://bit.ly/9Pjgjm


Oct 27, 2010 at 2:50 PM // reply »
11,238 Comments

@Paul,

Ha ha, awesome :)


May 6, 2012 at 12:32 PM // reply »
10 Comments

I actually didn't know about PrecisionEvaluate() till today! Greg Moser introduced it to me. We were looking at some simple math that rocked our world!

Try this for fun:

cfdump var="#89.95 + 13.29 eq 103.24#" ==> false

cfdump var="#PrecisionEvaluate(89.95 + 13.29) eq 103.24#" ==> true

This is math issue. Supposedly, there is only finite set of floating point values that can be represented by computers.

So, you can really never accurately do equality comparisons on FP values.

Good Read:
http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems


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 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools