How to overcome precision issue when cf/lucee is not strongly typed?

The following code in cfscript attempts to calculate probability of certain thing, please take a look at comment out original code as well.

<cfscript>
// function AttackerSuccessProbability(double q, int z) {
 function AttackerSuccessProbability(q, z) {
  // double p = 1.0 - q;  
	p = 1.0 - q; 	
		// double lambda = z * (q / p);    
		 lambda = z * (q / p); 
		// double sum = 1.0; 
		 sum = 1.0;	
		// int i, k; 
		for (k = 0; k <= z; k++)    {        
		  // double poisson = exp(-lambda);  
			poisson = exp(-lambda);		   
		   for (i = 1; i <= k; i++)            
		   poisson *= lambda / i;        
		  // sum -= poisson * (1 - pow(q / p, z - k));    
		  sum -= poisson * (1 - (q / p)^(z - k)); 
		   }    
		 // return sum;
		 writeOutput(sum); writeOutput("<br>");
}

AttackerSuccessProbability(0.01,0);
AttackerSuccessProbability(0.01,1);
AttackerSuccessProbability(0.01,2);
AttackerSuccessProbability(0.01,3);
AttackerSuccessProbability(0.01,4);
AttackerSuccessProbability(0.01,5);

writeOutput("<br>");

AttackerSuccessProbability(0.03,0);
AttackerSuccessProbability(0.03,5);
AttackerSuccessProbability(0.03,10);
AttackerSuccessProbability(0.03,15);
AttackerSuccessProbability(0.03,20);
AttackerSuccessProbability(0.03,25);

</cfscript>

The above generates the following respective results:

1
0.020049659504
0.000501302822
0.000013032317
0.000000344131
0.000000009161

1
0.000002232864
0.000000000008
0
0
0

Expected respective results:

q=0.1 z=0 P=1.0000000
z=1 P=0.2045873
z=2 P=0.0509779
z=3 P=0.0131722
z=4 P=0.0034552
z=5 P=0.0009137

q=0.3 z=0
P=1.0000000
z=5
P=0.1773523
z=10
P=0.0416605
z=15
P=0.0101008
z=20
P=0.0024804
z=25 P=0.0006132

Question, is there a way to substitute the “double” type or another technique to achieve more accurate results with cf or lucee?

Thanks.

Give precisionEvaluate() a try.

HTH

– Denny

2 Likes

My Lucee 5.2.8.50 does not have this function, how can I try/use it? ACF 2018 failed, Lucee 5.x also failed.

There is a video of the Lucee Team telling about the function with some explanations and details:

Video about precisionEvaluate()

2 Likes

I corrected the syntax error of using precisionEvaluate function, now it ran, however, I received exact same results as without using this function. Probably the inability of defining a variable type such as double compromises calculation.

Thanks tho.

I highly doubt you’re having a precision error. Even your first one is off by a factor of 10. That’s not going to happen with datatype precision issues.

Consider the following java/groovy:

double asp(double q, double z) {
  double p = 1.0 - q;
  double lambda = z * (q / p);
  double sum = 1.0;
  for (int k = 0; k<= z; k++) {
    double poisson = Math.exp(-lambda);
    for (int i=1; i<=k; i++) poisson *= lambda/i;
    sum -= poisson * (1 - Math.pow(q/p, z-k));
  }
  return sum
}

println asp(0.01,0);
println asp(0.01,1);
println asp(0.01,2);
println asp(0.01,3);
println asp(0.01,4);
println asp(0.01,5);

println asp(0.03,0);
println asp(0.03,5);
println asp(0.03,10);
println asp(0.03,15);
println asp(0.03,20);
println asp(0.03,25);

Which returns

1.0
0.020049659504318806
5.013028220883682E-4
1.3032317209471967E-5
3.441313628404327E-7
9.16142495488797E-9
1.0
2.23286394471924E-6
7.594443494968615E-12
4.114048166194166E-17
3.377117068551428E-17
5.670651046519856E-17

Which is what Lucee calculated.

Check your math.

Even better, notice that your CODE is off by a factor of 10.

You supplied the value 0.01 as q, but your expected results are for 0.1.

Can you output result such as the follwing

5.013028220883682E-4

into human readable format such as

0.020049659504318806

Thanks.

Sure

Change println asp(x,x); to printf("%.20f\n", asp(x,x));

0.01

1.00000000000000000000
0.02004965950431880600
0.00050130282208836820
0.00001303231720947197
0.00000034413136284043
0.00000000916142495489

.03

1.00000000000000000000
0.06044040671140482600
0.00453344350950214000
0.00035337426473033320
0.00002797576996010367
0.00000223286394471924

.1

1.00000000000000000000
0.20458727394278242000
0.05097789283933862000
0.01317224167889648200
0.00345524346648517360
0.00091368218792791220

But like I said, the problem isn’t with Lucee’s math. It’s that you provided the wrong arguments to your function. You want 0.1, not 0.01.

Any precision errors would be a loss of precision from the LEAST significant side, not the MOST significant side.

Using BigDecimal (i.e. precisionEvaluate) provides “infinite” precision… but even Lucee caps that at 20 decimal places.

https://www.webopedia.com/TERM/F/floating_point_number.html

2 Likes

You’re exactly right, I passed the parameter of 0.01 (wrong) instead of 0.1 (correct). Now, even without double type, we get almost good results.

Many thanks,.

interesting !