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

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.

Looking For a New Job?

25% of job board revenue is donated to Kiva. Loans that change lives - Find out more »

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

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

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

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 »

@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 »

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

http://bit.ly/9Pjgjm

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

@Paul,

Ha ha, awesome :)

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

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.

Dec 18, 2013 at 9:58 AM // reply »

I am a big fan, Ben. Your blog is my go to source when I need to deconstruct a serious challenge. Thank you, thank you! And, your posters are just as informed and informative. You've got a great thing going here.

I came across this post while researching PrecisionEvaluate(). Here's another shocker:

• <cfset x=16.4>
• <cfset y=x*100>
• <cfset z=int(y)>
• <cfoutput>#y#,#z#</cfoutput>

In cf9, at least, you'll get "1640,1639". I've just had a bug request labeled as "NotABug" and withdrawn because this is the fault of a floating point calculation. It was suggested that "If I require precision", I should use PrecisionEvaluate() around the inner value in int().

Anyone else run across this, because that's pretty unintuitive, and certainly not commonly recommended practice..? Makes me wonder how many inaccurate values I'm creating by using basic arithmetic functions. I'm now doubting each of the thousands of uses of int() and round(),etc. I've written into our code over the years. Details on this feature are here:

Who doesn't need precision?

Forewarned is forearmed, eh? ;)

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: bold   italic   code Remember my information Subscribe to comments Send me a copy of this comment
InVision App - Prototyping Made Beautiful With Prototyping Tools Recent Blog Comments
Mar 9, 2014 at 10:55 AM
\$.stop() vs. \$.finish() In jQuery Animations
Nice feature! Thanks for sharing. :) Good for when you are making a 100% AJAX controlled site. ... read »
Mar 9, 2014 at 12:26 AM
Experimenting With Multiple Class Inheritance In Javascript
@bigboomshakala, Hi, I am want present so solution for multiple prototypical inheritance, but some restrictions. Please follow the link: http://arto8.site11.com/ArtoJS/multi-inheritance-prototype.ph ... read »
Mar 8, 2014 at 5:21 PM
Thoroughly Document Your Use Of ColdFusion's CFHTMLHead Tag
hi Ben, how can we mention our own custom tags instead of using HTML tags in coldfusion? kindly revert with an example. ... read »
Mar 8, 2014 at 1:28 PM
Experimenting With Multiple Class Inheritance In Javascript
Hi, Agree with Artavazd, it's not inheritance. The proof : console.log(ben instanceof Person) // false console.log(ben instanceof Monkey) // false console.log(ben instanceof Ben) // true If " ... read »
Mar 7, 2014 at 8:31 PM
Sanity Check: \$index vs. DOM In AngularJS Directives
I had NOOOO idea you could pass the entire friend object into a method like this: removeFriend( friend ) . I was always using some ID of the object and passing that around back and forth between vie ... read »
Mar 7, 2014 at 10:43 AM
Project HUGE: Active Release Technique (ART) With Dr. Christopher Anselmi In NYC
Does anyone know of a GOOD A.R.T. Provider near the Binghamton,NY area? I have gone to a couple of people that said they do ART but they don't. It's just a massage. Thanks for any help you can give ... read »
Mar 7, 2014 at 8:44 AM
GMail Seems To Ignore The Return-Path Header Defined By The CFMail FailTo Attribute
So, is the header "Problems-to" no longer valid? I also add "return-path" via cfmailparam. ... read »
Mar 6, 2014 at 8:58 PM
Posting XML With ColdFusion, CFHttp, And CFHttpParam
ERROR2: Missing type node :( ... read »