View Javadoc

1   /*
2   *   org.galagosearch.eval.stat note:
3   *       This is an abridged version of the Stat class provided by Dr. Michael Flanagan.
4   *       The full version contains many more features.  This class has been trimmed to
5   *       contain primarily the functions necessary for IR evaluation.
6   *          http://www.ee.ucl.ac.uk/~mflanaga/java/
7   *
8   *   Class   Stat
9   *
10  *   USAGE:  Statistical functions
11  *
12  *   WRITTEN BY: Dr Michael Thomas Flanagan
13  *
14  *   DATE:    June 2002 as part of Fmath
15  *   AMENDED: 12 May 2003 Statistics separated out from Fmath as a new class
16  *   UPDATE:  18 June 2005, 5 January 2006, 25 April 2006, 12, 21 November 2006
17  *
18  *   DOCUMENTATION:
19  *   See Michael Thomas Flanagan's Java library on-line web page:
20  *   Stat.html
21  *
22  *   Copyright (c) April 2004, June 2005, January 2006, November 2006
23  *
24  *   PERMISSION TO COPY:
25  *   Permission to use, copy and modify this software and its documentation for
26  *   NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement
27  *   to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies.
28  *
29  *   Dr Michael Thomas Flanagan makes no representations about the suitability
30  *   or fitness of the software for any or for a particular purpose.
31  *   Michael Thomas Flanagan shall not be liable for any damages suffered
32  *   as a result of using, modifying or distributing this software or its derivatives.
33  *
34  ***************************************************************************************/
35  
36  package org.galagosearch.core.eval.stat;
37  
38  import java.util.*;
39  
40  public class Stat{
41  
42  
43          // A small number close to the smallest representable floating point number
44          public static final double FPMIN = 1e-300;
45  
46          // PRIVATE MEMBERS FOR USE IN GAMMA FUNCTION METHODS AND HISTOGRAM CONSTRUCTION METHODS
47  
48          // GAMMA FUNCTIONS
49          //  Lanczos Gamma Function approximation - N (number of coefficients -1)
50          private static int lgfN = 6;
51          //  Lanczos Gamma Function approximation - Coefficients
52          private static double[] lgfCoeff = {1.000000000190015, 76.18009172947146, -86.50532032941677, 24.01409824083091, -1.231739572450155, 0.1208650973866179E-2, -0.5395239384953E-5};
53          //  Lanczos Gamma Function approximation - small gamma
54          private static double lgfGamma = 5.0;
55          //  Maximum number of iterations allowed in Incomplete Gamma Function calculations
56          private static int igfiter = 1000;
57          //  Tolerance used in terminating series in Incomplete Gamma Function calculations
58          private static double igfeps = 1e-8;
59  
60          // HISTOGRAM CONSTRUCTION
61          //  Tolerance used in including an upper point in last histogram bin when it is outside due to riunding erors
62          private static double histTol = 1.0001D;
63  
64          // METHODS
65  
66          // Arithmetic mean of a 1D array of doubles, aa
67          public static double mean(double[] aa){
68                  int n = aa.length;
69                  double sum=0.0D;
70                  for(int i=0; i<n; i++){
71                          sum+=aa[i];
72                  }
73                  return sum/((double)n);
74          }
75  
76          // Weighted arithmetic mean of a 1D array of doubles, aa
77          public static double mean(double[] aa, double[] ww){
78                  int n = aa.length;
79                  if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different");
80                  double sumx=0.0D;
81                  double sumw=0.0D;
82                  double weight = 0.0D;
83                  for(int i=0; i<n; i++){
84                      weight = 1.0D/(ww[i]*ww[i]);
85                      sumx+=aa[i]*weight;
86                      sumw+=weight;
87                  }
88                  return sumx/sumw;
89          }
90  
91          // Weighted arithmetic mean of a 1D array of floats, aa
92          public static double mean(float[] aa, float[] ww){
93                  int n = aa.length;
94                  if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different");
95                  float sumx=0.0F;
96                  float sumw=0.0F;
97                  float weight = 0.0F;
98                  for(int i=0; i<n; i++){
99                      weight = 1.0F/(ww[i]*ww[i]);
100                     sumx+=aa[i]*weight;
101                     sumw+=weight;
102                 }
103                 return sumx/sumw;
104         }
105 
106         // Geometric mean of a 1D array of doubles, aa
107         public static double geometricMean(double[] aa){
108                 int n = aa.length;
109                 double product=1.0D;
110                 for(int i=0; i<n; i++)product *= Math.pow(aa[i], 1.0D/((double)n));
111                 return product;
112         }
113 
114         // Geometric mean of a 1D array of floats, aa
115         public static float geometricMean(float[] aa){
116                 int n = aa.length;
117                 float product=1.0F;
118                 for(int i=0; i<n; i++)product *= (float)Math.pow(aa[i], 1.0F/((float)n));
119                 return product;
120         }
121 
122         // Weighted geometric mean of a 1D array of doubles, aa
123         public static double geometricMean(double[] aa, double[] ww){
124                 int n = aa.length;
125                 double sumW = 0.0D;
126                 double[] weight = new double[n];
127                 for(int i=0; i<n; i++){
128                     weight[i]=1.0D/(ww[i]*ww[i]);
129                     sumW += ww[i];
130                 }
131                 double product=1.0D;
132                 for(int i=0; i<n; i++){
133                     product *= Math.pow(aa[i], weight[i]/sumW);
134                 }
135                 return product;
136         }
137 
138         // Weighted geometric mean of a 1D array of floats, aa
139         public static float geometricMean(float[] aa, float[] ww){
140                 int n = aa.length;
141                 float sumW = 0.0F;
142                 float[] weight = new float[n];
143                 for(int i=0; i<n; i++){
144                     weight[i]=1.0F/(ww[i]*ww[i]);
145                     sumW += ww[i];
146                 }
147                 float product=1.0F;
148                 for(int i=0; i<n; i++){
149                     product *= (float)Math.pow(aa[i], weight[i]/sumW);
150                 }
151                 return product;
152         }
153 
154         // Harmonic mean of a 1D array of doubles, aa
155         public static double harmonicMean(double[] aa){
156                 int n = aa.length;
157                 double sum = 0.0D;
158                 for(int i=0; i<n; i++)sum += 1.0D/aa[i];
159                 return (double)n/sum;
160         }
161 
162         // Harmonic mean of a 1D array of floats, aa
163         public static float harmonicMean(float[] aa){
164                 int n = aa.length;
165                 float sum = 0.0F;
166                 for(int i=0; i<n; i++)sum += 1.0F/aa[i];
167                 return (float)n/sum;
168         }
169 
170         // Weighted harmonic mean of a 1D array of doubles, aa
171         public static double harmonicMean(double[] aa, double[] ww){
172                 int n = aa.length;
173                 double sum = 0.0D;
174                 double sumW = 0.0D;
175                 double[] weight = new double[n];
176                 for(int i=0; i<n; i++){
177                     sumW += ww[i];
178                     weight[i]=1.0D/(ww[i]*ww[i]);
179                 }
180                 for(int i=0; i<n; i++)sum += ww[i]/aa[i];
181                 return sumW/sum;
182         }
183 
184         // Weighted harmonic mean of a 1D array of floats, aa
185         public static float harmonicMean(float[] aa, float[] ww){
186                 int n = aa.length;
187                 float sum = 0.0F;
188                 float sumW = 0.0F;
189                 float[] weight = new float[n];
190                 for(int i=0; i<n; i++){
191                     sumW += ww[i];
192                     weight[i]=1.0F/(ww[i]*ww[i]);
193                 }
194                 for(int i=0; i<n; i++)sum += ww[i]/aa[i];
195                 return sumW/sum;
196         }
197 
198         // Generalised mean of a 1D array of doubles, aa
199         public static double generalisedMean(double[] aa, double m){
200                 int n = aa.length;
201                 double sum=0.0D;
202                 for(int i=0; i<n; i++){
203                         sum += Math.pow(aa[i],m);
204                 }
205                 return Math.pow(sum/((double)n), 1.0D/m);
206         }
207 
208         // Generalised mean of a 1D array of floats, aa
209         public static float generalisedMean(float[] aa, float m){
210                 int n = aa.length;
211                 float sum=0.0F;
212                 for(int i=0; i<n; i++){
213                         sum += Math.pow(aa[i],m);
214                 }
215                 return (float)Math.pow(sum/((float)n), 1.0F/m);
216         }
217 
218         // Interquartile mean of a 1D array of doubles, aa
219         public static double interQuartileMean(double[] aa){
220                 int n = aa.length;
221                 if(n<4)throw new IllegalArgumentException("At least 4 array elements needed");
222                 double[] bb = Fmath.selectionSort(aa);
223                 double sum = 0.0D;
224                 for(int i=n/4; i<3*n/4; i++)sum += bb[i];
225                 return 2.0*sum/(double)(n);
226         }
227 
228         // Interquartile mean of a 1D array of floats, aa
229         public static float interQuartileMean(float[] aa){
230                 int n = aa.length;
231                 if(n<4)throw new IllegalArgumentException("At least 4 array elements needed");
232                 float[] bb = Fmath.selectionSort(aa);
233                 float sum = 0.0F;
234                 for(int i=n/4; i<3*n/4; i++)sum += bb[i];
235                 return 2.0F*sum/(float)(n);
236         }
237 
238        // Root mean square (rms) of a 1D array of doubles, aa
239         public static double rms(double[] aa){
240                 int n = aa.length;
241                 double sum=0.0D;
242                 for(int i=0; i<n; i++){
243                         sum+=aa[i]*aa[i];
244                 }
245                 return Math.sqrt(sum/((double)n));
246         }
247 
248         // Root mean square (rms) of a 1D array of floats, aa
249         public static float rms(float[] aa){
250                 int n = aa.length;
251                 float sum = 0.0F;
252                 for(int i=0; i<n; i++){
253                         sum+=aa[i]*aa[i];
254                 }
255                 sum /= (float)n;
256 
257                 return (float)Math.sqrt(sum);
258         }
259 
260         // Arithmetic mean of a 1D array of floats, aa
261         public static float mean(float[] aa){
262                 int n = aa.length;
263                 float sum=0.0F;
264                 for(int i=0; i<n; i++){
265                         sum+=aa[i];
266                 }
267                 return sum/((float)n);
268         }
269 
270         // Arithmetic mean of a 1D array of int, aa
271         public static double mean(int[] aa){
272                 int n = aa.length;
273                 double sum=0.0D;
274                 for(int i=0; i<n; i++){
275                         sum+=(double)aa[i];
276                 }
277                 return sum/((double)n);
278         }
279 
280              // Arithmetic mean of a 1D array of long, aa
281         public static double mean(long[] aa){
282                 int n = aa.length;
283                 double sum=0.0D;
284                 for(int i=0; i<n; i++){
285                         sum+=(double)aa[i];
286                 }
287                 return sum/((double)n);
288         }
289 
290         // Median of a 1D array of doubles, aa
291         public static double median(double[] aa){
292                 int n = aa.length;
293                 int nOverTwo = n/2;
294                 double med = 0.0D;
295                 double[] bb = Fmath.selectionSort(aa);
296                 if(Fmath.isOdd(n)){
297                     med = bb[nOverTwo];
298                 }
299                 else{
300                     med = (bb[nOverTwo-1]+bb[nOverTwo])/2.0D;
301                 }
302 
303                 return med;
304         }
305 
306         // Median of a 1D array of floats, aa
307         public static float median(float[] aa){
308                 int n = aa.length;
309                 int nOverTwo = n/2;
310                 float med = 0.0F;
311                 float[] bb = Fmath.selectionSort(aa);
312                 if(Fmath.isOdd(n)){
313                     med = bb[nOverTwo];
314                 }
315                 else{
316                     med = (bb[nOverTwo-1]+bb[nOverTwo])/2.0F;
317                 }
318 
319                 return med;
320         }
321 
322         // Median of a 1D array of int, aa
323         public static double median(int[] aa){
324                 int n = aa.length;
325                 int nOverTwo = n/2;
326                 double med = 0.0D;
327                 int[] bb = Fmath.selectionSort(aa);
328                 if(Fmath.isOdd(n)){
329                     med = (double)bb[nOverTwo];
330                 }
331                 else{
332                     med = (double)(bb[nOverTwo-1]+bb[nOverTwo])/2.0D;
333                 }
334 
335                 return med;
336         }
337 
338         // Median of a 1D array of long, aa
339         public static double median(long[] aa){
340                 int n = aa.length;
341                 int nOverTwo = n/2;
342                 double med = 0.0D;
343                 long[] bb = Fmath.selectionSort(aa);
344                 if(Fmath.isOdd(n)){
345                     med = (double)bb[nOverTwo];
346                 }
347                 else{
348                     med = (double)(bb[nOverTwo-1]+bb[nOverTwo])/2.0D;
349                 }
350 
351                 return med;
352         }
353 
354         // Standard deviation of a 1D array of doubles, aa
355         public static double standardDeviation(double[] aa){
356                 return Math.sqrt(variance(aa));
357         }
358 
359         // Standard deviation of a 1D array of floats, aa
360         public static float standardDeviation(float[] aa){
361                 return (float)Math.sqrt(variance(aa));
362         }
363 
364         // Standard deviation of a 1D array of int, aa
365         public static double standardDeviation(int[] aa){
366                 return Math.sqrt(variance(aa));
367         }
368 
369         // Standard deviation of a 1D array of long, aa
370         public static double standardDeviation(long[] aa){
371                 return Math.sqrt(variance(aa));
372         }
373 
374         // Weighted standard deviation of a 1D array of doubles, aa
375         public static double standardDeviation(double[] aa, double[] ww){
376                 if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different");
377                 return Math.sqrt(variance(aa, ww));
378         }
379 
380         // Weighted standard deviation of a 1D array of floats, aa
381         public static float standardDeviation(float[] aa, float[] ww){
382                 if(aa.length!=ww.length)throw new IllegalArgumentException("length of variable array, " + aa.length + " and length of weight array, " + ww.length + " are different");
383                 return (float)Math.sqrt(variance(aa, ww));
384         }
385 
386 
387 
388         // volatility   log  (doubles)
389         public static double volatilityLogChange(double[] array){
390             int n = array.length-1;
391             double[] change = new double[n];
392             for(int i=0; i<n; i++)change[i] = Math.log(array[i+1]/array[i]);
393             return Stat.standardDeviation(change);
394         }
395 
396         // volatility   log  (floats)
397         public static float volatilityLogChange(float[] array){
398             int n = array.length-1;
399             float[] change = new float[n];
400             for(int i=0; i<n; i++)change[i] = (float)Math.log(array[i+1]/array[i]);
401             return Stat.standardDeviation(change);
402         }
403 
404         // volatility   percentage (double)
405         public static double volatilityPerCentChange(double[] array){
406             int n = array.length-1;
407             double[] change = new double[n];
408             for(int i=0; i<n; i++)change[i] = (array[i+1] - array[i])*100.0D/array[i];
409             return Stat.standardDeviation(change);
410         }
411 
412         // volatility   percentage (float)
413         public static double volatilityPerCentChange(float[] array){
414             int n = array.length-1;
415             float[] change = new float[n];
416             for(int i=0; i<n; i++)change[i] = (array[i+1] - array[i])*100.0F/array[i];
417             return Stat.standardDeviation(change);
418         }
419 
420         // Coefficient of variation of an array of doubles
421         public static double coefficientOfVariation(double[] array){
422             return 100.0D*Stat.standardDeviation(array)/Math.abs(Stat.mean(array));
423         }
424 
425         // Coefficient of variation of an array of float
426         public static float coefficientOfVariation(float[] array){
427             return 100.0F*Stat.standardDeviation(array)/Math.abs(Stat.mean(array));
428         }
429 
430         // Subtract mean of an array from data array elements
431         public static double[] subtractMean(double[] array){
432             int n = array.length;
433             double mean = Stat.mean(array);
434             double[] arrayMinusMean = new double[n];
435             for(int i=0; i<n; i++)arrayMinusMean[i] = array[i] - mean;
436 
437             return arrayMinusMean;
438         }
439 
440         // Subtract mean of an array from data array elements
441         public static float[] subtractMean(float[] array){
442             int n = array.length;
443             float mean = Stat.mean(array);
444             float[] arrayMinusMean = new float[n];
445             for(int i=0; i<n; i++)arrayMinusMean[i] = array[i] - mean;
446 
447             return arrayMinusMean;
448         }
449 
450         // Variance of a 1D array of doubles, aa
451         public static double variance(double[] aa){
452                 int n = aa.length;
453                 double sum=0.0D, mean=0.0D;
454                 for(int i=0; i<n; i++){
455                         sum+=aa[i];
456                 }
457                 mean=sum/((double)n);
458                 sum=0.0D;
459                 for(int i=0; i<n; i++){
460                         sum+=Fmath.square(aa[i]-mean);
461                 }
462                 return sum/((double)(n-1));
463         }
464 
465         // Variance of a 1D array of floats, aa
466         public static float variance(float[] aa){
467                 int n = aa.length;
468                 float sum=0.0F, mean=0.0F;
469                 for(int i=0; i<n; i++){
470                         sum+=aa[i];
471                 }
472                 mean=sum/((float)n);
473                 sum=0.0F;
474                 for(int i=0; i<n; i++){
475                         sum+=Fmath.square(aa[i]-mean);
476                 }
477                 return sum/((float)(n-1));
478         }
479 
480        // Variance of a 1D array of int, aa
481         public static double variance(int[] aa){
482                 int n = aa.length;
483                 double sum=0.0D, mean=0.0D;
484                 for(int i=0; i<n; i++){
485                         sum+=(double)aa[i];
486                 }
487                 mean=sum/((double)n);
488                 sum=0.0D;
489                 for(int i=0; i<n; i++){
490                         sum+=Fmath.square((double)aa[i]-mean);
491                 }
492                 return sum/((double)(n-1));
493         }
494 
495        // Variance of a 1D array of ilong, aa
496         public static double variance(long[] aa){
497                 int n = aa.length;
498                 double sum=0.0D, mean=0.0D;
499                 for(int i=0; i<n; i++){
500                         sum+=(double)aa[i];
501                 }
502                 mean=sum/((double)n);
503                 sum=0.0D;
504                 for(int i=0; i<n; i++){
505                         sum+=Fmath.square((double)aa[i]-mean);
506                 }
507                 return sum/((double)(n-1));
508         }
509 
510         // Weighted variance of a 1D array of doubles, aa
511         public static double variance(double[] aa, double[] ww){
512                 int n = aa.length;
513                 if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different");
514                 double sumx=0.0D, sumw=0.0D, mean=0.0D;
515                 double[] weight = new double[n];
516                 for(int i=0; i<n; i++){
517                         sumx+=aa[i];
518                         weight[i]=1.0D/(ww[i]*ww[i]);
519                         sumw+=weight[i];
520                 }
521                 mean=sumx/sumw;
522                 sumx=0.0D;
523                 for(int i=0; i<n; i++){
524                         sumx+=weight[i]*Fmath.square(aa[i]-mean);
525                 }
526                 return sumx*(double)(n)/((double)(n-1)*sumw);
527         }
528 
529         // Weighted variance of a 1D array of floats, aa
530         public static float variance(float[] aa, float[] ww){
531                 int n = aa.length;
532                 if(n!=ww.length)throw new IllegalArgumentException("length of variable array, " + n + " and length of weight array, " + ww.length + " are different");
533                 float sumx=0.0F, sumw=0.0F, mean=0.0F;
534                 float[] weight = new float[n];
535                 for(int i=0; i<n; i++){
536                         sumx+=aa[i];
537                         weight[i]=1.0F/(ww[i]*ww[i]);
538                         sumw+=weight[i];
539                 }
540                 mean=sumx/sumw;
541                 sumx=0.0F;
542                 for(int i=0; i<n; i++){
543                         sumx+=weight[i]*Fmath.square(aa[i]-mean);
544                 }
545                 return sumx*(float)(n)/((float)(n-1)*sumw);
546         }
547 
548         // Covariance of two 1D arrays of doubles, xx and yy
549         public static double covariance(double[] xx, double[] yy){
550                 int n = xx.length;
551                 if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different");
552 
553                 double sumx=0.0D, meanx=0.0D;
554                 double sumy=0.0D, meany=0.0D;
555                 for(int i=0; i<n; i++){
556                         sumx+=xx[i];
557                         sumy+=yy[i];
558                 }
559                 meanx=sumx/((double)n);
560                 meany=sumy/((double)n);
561                 double sum=0.0D;
562                 for(int i=0; i<n; i++){
563                         sum+=(xx[i]-meanx)*(yy[i]-meany);
564                 }
565                 return sum/((double)(n-1));
566         }
567 
568         // Covariance of two 1D arrays of floats, xx and yy
569         public static float covariance(float[] xx, float[] yy){
570                 int n = xx.length;
571                 if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different");
572 
573                 float sumx=0.0F, meanx=0.0F;
574                 float sumy=0.0F, meany=0.0F;
575                 for(int i=0; i<n; i++){
576                         sumx+=xx[i];
577                         sumy+=yy[i];
578                 }
579                 meanx=sumx/((float)n);
580                 meany=sumy/((float)n);
581                 float sum=0.0F;
582                 for(int i=0; i<n; i++){
583                         sum+=(xx[i]-meanx)*(yy[i]-meany);
584                 }
585                 return sum/((float)(n-1));
586         }
587 
588         // Covariance of two 1D arrays of ints, xx and yy
589         public static double covariance(int[] xx, int[] yy){
590                 int n = xx.length;
591                 if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different");
592 
593                 double sumx=0.0D, meanx=0.0D;
594                 double sumy=0.0D, meany=0.0D;
595                 for(int i=0; i<n; i++){
596                         sumx+=(double)xx[i];
597                         sumy+=(double)yy[i];
598                 }
599                 meanx=sumx/((double)n);
600                 meany=sumy/((double)n);
601                 double sum=0.0D;
602                 for(int i=0; i<n; i++){
603                         sum+=((double)xx[i]-meanx)*((double)yy[i]-meany);
604                 }
605                 return sum/((double)(n-1));
606         }
607 
608         // Covariance of two 1D arrays of ints, xx and yy
609         public static double covariance(long[] xx, long[] yy){
610                 int n = xx.length;
611                 if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different");
612 
613                 double sumx=0.0D, meanx=0.0D;
614                 double sumy=0.0D, meany=0.0D;
615                 for(int i=0; i<n; i++){
616                         sumx+=(double)xx[i];
617                         sumy+=(double)yy[i];
618                 }
619                 meanx=sumx/((double)n);
620                 meany=sumy/((double)n);
621                 double sum=0.0D;
622                 for(int i=0; i<n; i++){
623                         sum+=((double)xx[i]-meanx)*((double)yy[i]-meany);
624                 }
625                 return sum/((double)(n-1));
626         }
627 
628         // Weighted covariance of two 1D arrays of doubles, xx and yy with weights ww
629         public static double covariance(double[] xx, double[] yy, double[] ww){
630                 int n = xx.length;
631                 if(n!=yy.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of y array, " + yy.length + " are different");
632                 if(n!=ww.length)throw new IllegalArgumentException("length of x variable array, " + n + " and length of weight array, " + yy.length + " are different");
633                 double sumx=0.0D, sumy=0.0D, sumw=0.0D, meanx=0.0D, meany=0.0D;
634                 double[] weight = new double[n];
635                 for(int i=0; i<n; i++){
636                         sumx+=xx[i];
637                         sumy+=yy[i];
638                         weight[i]=1.0D/(ww[i]*ww[i]);
639                         sumw+=weight[i];
640                 }
641                 meanx=sumx/sumw;
642                 meany=sumy/sumw;
643 
644                 double sum=0.0D;
645                 for(int i=0; i<n; i++){
646                         sum+=weight[i]*(xx[i]-meanx)*(yy[i]-meany);
647                 }
648                 return sum*(double)(n)/((double)(n-1)*sumw);
649         }
650 
651         //
652 
653         // Gamma function
654         // Lanczos approximation (6 terms)
655         public static double gamma(double x){
656 
657                 double xcopy = x;
658                 double first = x + lgfGamma + 0.5;
659                 double second = lgfCoeff[0];
660                 double fg = 0.0D;
661 
662                 if(x>=0.0){
663                         if(x>=1.0D && x-(int)x==0.0D){
664                                 fg = Stat.factorial(x)/x;
665                         }
666                         else{
667                                 first = Math.pow(first, x + 0.5)*Math.exp(-first);
668                                 for(int i=1; i<=lgfN; i++)second += lgfCoeff[i]/++xcopy;
669                                 fg = first*Math.sqrt(2.0*Math.PI)*second/x;
670                         }
671                 }
672                 else{
673                          fg = -Math.PI/(x*Stat.gamma(-x)*Math.sin(Math.PI*x));
674                 }
675                 return fg;
676         }
677 
678         // Return the Lanczos constant gamma
679         public static double getLanczosGamma(){
680                 return Stat.lgfGamma;
681         }
682 
683         // Return the Lanczos constant N (number of coeeficients + 1)
684         public static int getLanczosN(){
685                 return Stat.lgfN;
686         }
687 
688         // Return the Lanczos coeeficients
689         public static double[] getLanczosCoeff(){
690                 int n = Stat.getLanczosN()+1;
691                 double[] coef = new double[n];
692                 for(int i=0; i<n; i++){
693                         coef[i] = Stat.lgfCoeff[i];
694                 }
695                 return coef;
696         }
697 
698         // Return the nearest smallest representable floating point number to zero with mantissa rounded to 1.0
699         public static double getFpmin(){
700                 return Stat.FPMIN;
701         }
702 
703         // log to base e of the Gamma function
704         // Lanczos approximation (6 terms)
705         public static double logGamma(double x){
706                 double xcopy = x;
707                 double fg = 0.0D;
708                 double first = x + lgfGamma + 0.5;
709                 double second = lgfCoeff[0];
710 
711                 if(x>=0.0){
712                         if(x>=1.0 && x-(int)x==0.0){
713                                 fg = Stat.logFactorial(x)-Math.log(x);
714                         }
715                         else{
716                                 first -= (x + 0.5)*Math.log(first);
717                                 for(int i=1; i<=lgfN; i++)second += lgfCoeff[i]/++xcopy;
718                                 fg = Math.log(Math.sqrt(2.0*Math.PI)*second/x) - first;
719                         }
720                 }
721                 else{
722                         fg = Math.PI/(Stat.gamma(1.0D-x)*Math.sin(Math.PI*x));
723 
724                         if(fg!=1.0/0.0 && fg!=-1.0/0.0){
725                                 if(fg<0){
726                                          throw new IllegalArgumentException("\nThe gamma function is negative");
727                                 }
728                                 else{
729                                         fg = Math.log(fg);
730                                 }
731                         }
732                 }
733                 return fg;
734         }
735 
736         // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt
737         public static double incompleteGamma(double a, double x){
738                 if(a<0.0D  || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0");
739                 double igf = 0.0D;
740 
741                 if(x < a+1.0D){
742                         // Series representation
743                         igf = incompleteGammaSer(a, x);
744                 }
745                 else{
746                         // Continued fraction representation
747                         igf = incompleteGammaFract(a, x);
748                 }
749                 return igf;
750         }
751 
752         // Complementary Incomplete Gamma Function Q(a,x) = 1 - P(a,x) = 1 - integral from zero to x of (exp(-t)t^(a-1))dt
753         // Also known as the Incomplete Gamma Function
754         public static double incompleteGammaComplementary(double a, double x){
755                 if(a<0.0D  || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0");
756                 double igf = 0.0D;
757 
758                 if(x!=0.0D){
759                         if(x==1.0D/0.0D)
760                         {
761                                 igf=1.0D;
762                         }
763                         else{
764                                 if(x < a+1.0D){
765                                         // Series representation
766                                         igf = 1.0D - incompleteGammaSer(a, x);
767                                 }
768                                 else{
769                                         // Continued fraction representation
770                                         igf = 1.0D - incompleteGammaFract(a, x);
771                                 }
772                         }
773                 }
774                 return igf;
775         }
776 
777         // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt
778         // Series representation of the function - valid for x < a + 1
779         public static double incompleteGammaSer(double a, double x){
780                 if(a<0.0D  || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0");
781                 if(x>=a+1) throw new IllegalArgumentException("\nx >= a+1   use Continued Fraction Representation");
782 
783                 int i = 0;
784                 double igf = 0.0D;
785                 boolean check = true;
786 
787                 double acopy = a;
788                 double sum = 1.0/a;
789                 double incr = sum;
790                 double loggamma = Stat.logGamma(a);
791 
792                 while(check){
793                         ++i;
794                         ++a;
795                         incr *= x/a;
796                         sum += incr;
797                         if(Math.abs(incr) < Math.abs(sum)*Stat.igfeps){
798                                 igf = sum*Math.exp(-x+acopy*Math.log(x)- loggamma);
799                                 check = false;
800                         }
801                         if(i>=Stat.igfiter){
802                                 check=false;
803                                 igf = sum*Math.exp(-x+acopy*Math.log(x)- loggamma);
804                                 System.out.println("\nMaximum number of iterations were exceeded in Stat.incompleteGammaSer().\nCurrent value returned.\nIncrement = "+String.valueOf(incr)+".\nSum = "+String.valueOf(sum)+".\nTolerance =  "+String.valueOf(igfeps));
805                         }
806                 }
807                 return igf;
808         }
809 
810         // Regularised Incomplete Gamma Function P(a,x) = integral from zero to x of (exp(-t)t^(a-1))dt
811         // Continued Fraction representation of the function - valid for x >= a + 1
812         // This method follows the general procedure used in Numerical Recipes for C,
813         // The Art of Scientific Computing
814         // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery
815         // Cambridge University Press,   http://www.nr.com/
816         public static double incompleteGammaFract(double a, double x){
817                 if(a<0.0D  || x<0.0D)throw new IllegalArgumentException("\nFunction defined only for a >= 0 and x>=0");
818                 if(x<a+1) throw new IllegalArgumentException("\nx < a+1   Use Series Representation");
819 
820                 int i = 0;
821                 double ii = 0;
822                 double igf = 0.0D;
823                 boolean check = true;
824 
825                 double loggamma = Stat.logGamma(a);
826                 double numer = 0.0D;
827                 double incr = 0.0D;
828                 double denom = x - a + 1.0D;
829                 double first = 1.0D/denom;
830                 double term = 1.0D/FPMIN;
831                 double prod = first;
832 
833                 while(check){
834                         ++i;
835                         ii = (double)i;
836                         numer = -ii*(ii - a);
837                         denom += 2.0D;
838                         first = numer*first + denom;
839                         if(Math.abs(first) < Stat.FPMIN){
840                             first = Stat.FPMIN;
841                         }
842                         term = denom + numer/term;
843                         if(Math.abs(term) < Stat.FPMIN){
844                             term = Stat.FPMIN;
845                          }
846                         first = 1.0D/first;
847                         incr = first*term;
848                         prod *= incr;
849                         if(Math.abs(incr - 1.0D) < igfeps)check = false;
850                         if(i>=Stat.igfiter){
851                                 check=false;
852                                 System.out.println("\nMaximum number of iterations were exceeded in Stat.incompleteGammaFract().\nCurrent value returned.\nIncrement - 1 = "+String.valueOf(incr-1)+".\nTolerance =  "+String.valueOf(igfeps));
853                         }
854                 }
855                 igf = 1.0D - Math.exp(-x+a*Math.log(x)-loggamma)*prod;
856                 return igf;
857         }
858 
859         // Reset the maximum number of iterations allowed in the calculation of the incomplete gamma functions
860         public static void setIncGammaMaxIter(int igfiter){
861                 Stat.igfiter=igfiter;
862         }
863 
864         // Return the maximum number of iterations allowed in the calculation of the incomplete gamma functions
865         public static int getIncGammaMaxIter(){
866                 return Stat.igfiter;
867         }
868 
869         // Reset the tolerance used in the calculation of the incomplete gamma functions
870         public static void setIncGammaTol(double igfeps){
871                 Stat.igfeps=igfeps;
872         }
873 
874         // Return the tolerance used in the calculation of the incomplete gamm functions
875         public static double getIncGammaTol(){
876                 return Stat.igfeps;
877         }
878 
879         // Beta function
880         public static double beta(double z, double w){
881                 return Math.exp(logGamma(z) + logGamma(w) - logGamma(z + w));
882         }
883 
884         // Regularised Incomplete Beta function
885         // Continued Fraction approximation (see Numerical recipies for details of method)
886         public static double incompleteBeta(double z, double w, double x){
887             if(x<0.0D || x>1.0D)throw new IllegalArgumentException("Argument x, "+x+", must be lie between 0 and 1 (inclusive)");
888             double ibeta = 0.0D;
889             if(x==0.0D){
890                 ibeta=0.0D;
891             }
892             else{
893                 if(x==1.0D){
894                     ibeta=1.0D;
895                 }
896                 else{
897                     // Term before continued fraction
898                     ibeta = Math.exp(Stat.logGamma(z+w) - Stat.logGamma(z) - logGamma(w) + z*Math.log(x) + w*Math.log(1.0D-x));
899                     // Continued fraction
900                     if(x < (z+1.0D)/(z+w+2.0D)){
901                         ibeta = ibeta*Stat.contFract(z, w, x)/z;
902                     }
903                     else{
904                         // Use symmetry relationship
905                         ibeta = 1.0D - ibeta*Stat.contFract(w, z, 1.0D-x)/w;
906                     }
907                 }
908             }
909             return ibeta;
910         }
911 
912         // Incomplete fraction summation used in the method incompleteBeta
913         // modified Lentz's method
914         public static double contFract(double a, double b, double x){
915             int maxit = 500;
916             double eps = 3.0e-7;
917             double aplusb = a + b;
918             double aplus1 = a + 1.0D;
919             double aminus1 = a - 1.0D;
920             double c = 1.0D;
921             double d = 1.0D - aplusb*x/aplus1;
922             if(Math.abs(d)<Stat.FPMIN)d = FPMIN;
923             d = 1.0D/d;
924             double h = d;
925             double aa = 0.0D;
926             double del = 0.0D;
927             int i=1, i2=0;
928             boolean test=true;
929             while(test){
930                 i2=2*i;
931                 aa = i*(b-i)*x/((aminus1+i2)*(a+i2));
932                 d = 1.0D + aa*d;
933                 if(Math.abs(d)<Stat.FPMIN)d = FPMIN;
934                 c = 1.0D + aa/c;
935                 if(Math.abs(c)<Stat.FPMIN)c = FPMIN;
936                 d = 1.0D/d;
937                 h *= d*c;
938                 aa = -(a+i)*(aplusb+i)*x/((a+i2)*(aplus1+i2));
939                 d = 1.0D + aa*d;
940                 if(Math.abs(d)<Stat.FPMIN)d = FPMIN;
941                 c = 1.0D + aa/c;
942                 if(Math.abs(c)<Stat.FPMIN)c = FPMIN;
943                 d = 1.0D/d;
944                 del = d*c;
945                 h *= del;
946                 i++;
947                 if(Math.abs(del-1.0D) < eps)test=false;
948                 if(i>maxit){
949                     test=false;
950                     System.out.println("Maximum number of iterations ("+maxit+") exceeded in Stat.contFract in Stat.incomplete Beta");
951                 }
952             }
953             return h;
954 
955         }
956 
957         // Error Function
958         public static double erf(double x){
959                 double erf = 0.0D;
960                 if(x!=0.0){
961                         if(x==1.0D/0.0D){
962                                 erf = 1.0D;
963                         }
964                         else{
965                                 if(x>=0){
966                                         erf = Stat.incompleteGamma(0.5, x*x);
967                                 }
968                                 else{
969                                         erf = -Stat.incompleteGamma(0.5, x*x);
970                                 }
971                         }
972                 }
973                 return erf;
974         }
975 
976         // Complementary Error Function
977         public static double erfc(double x){
978                 double erfc = 1.0D;
979                 if(x!=0.0){
980                         if(x==1.0D/0.0D){
981                                 erfc = 0.0D;
982                         }
983                         else{
984                                 if(x>=0){
985                                         erfc = 1.0D - Stat.incompleteGamma(0.5, x*x);
986                                 }
987                                 else{
988                                         erfc = 1.0D + Stat.incompleteGamma(0.5, x*x);
989                                 }
990                         }
991                 }
992                 return erfc;
993         }
994 
995         // Gaussian (normal) cumulative distribution function
996         // probability that a variate will assume a value less than the upperlimit
997         // mean  =  the mean, sd = standard deviation
998         public static double normalProb(double mean, double sd, double upperlimit){
999                 double arg = (upperlimit - mean)/(sd*Math.sqrt(2.0));
1000                 return (1.0D + Stat.erf(arg))/2.0D;
1001         }
1002 
1003         // Gaussian (normal) cumulative distribution function
1004         // probability that a variate will assume a value less than the upperlimit
1005         // mean  =  the mean, sd = standard deviation
1006         public static double gaussianProb(double mean, double sd, double upperlimit){
1007                 double arg = (upperlimit - mean)/(sd*Math.sqrt(2.0));
1008                 return (1.0D + Stat.erf(arg))/2.0D;
1009         }
1010 
1011         // Gaussian (normal) cumulative distribution function
1012         // probability that a variate will assume a value between the lower and  the upper limits
1013         // mean  =  the mean, sd = standard deviation
1014         public static double normalProb(double mean, double sd, double lowerlimit, double upperlimit){
1015                 double arg1 = (lowerlimit - mean)/(sd*Math.sqrt(2.0));
1016                 double arg2 = (upperlimit - mean)/(sd*Math.sqrt(2.0));
1017 
1018                 return (Stat.erf(arg2)-Stat.erf(arg1))/2.0D;
1019         }
1020 
1021         // Gaussian (normal) cumulative distribution function
1022         // probability that a variate will assume a value between the lower and  the upper limits
1023         // mean  =  the mean, sd = standard deviation
1024         public static double gaussianProb(double mean, double sd, double lowerlimit, double upperlimit){
1025                 double arg1 = (lowerlimit - mean)/(sd*Math.sqrt(2.0));
1026                 double arg2 = (upperlimit - mean)/(sd*Math.sqrt(2.0));
1027 
1028                 return (Stat.erf(arg2)-Stat.erf(arg1))/2.0D;
1029         }
1030 
1031         // Gaussian (normal) probability
1032         // mean  =  the mean, sd = standard deviation
1033         public static double normal(double mean, double sd, double x){
1034                 return Math.exp(-Fmath.square((x - mean)/sd)/2.0)/(sd*Math.sqrt(2.0D*Math.PI));
1035         }
1036 
1037         // Gaussian (normal) probability
1038         // mean  =  the mean, sd = standard deviation
1039         public static double gaussian(double mean, double sd, double x){
1040                 return Math.exp(-Fmath.square((x - mean)/sd)/2.0)/(sd*Math.sqrt(2.0D*Math.PI));
1041         }
1042 
1043         // Returns an array of Gaussian (normal) random deviates - clock seed
1044         // mean  =  the mean, sd = standard deviation, length of array
1045         public static double[] normalRand(double mean, double sd, int n){
1046                 double[] ran = new double[n];
1047                 Random rr = new Random();
1048                 for(int i=0; i<n; i++){
1049                     ran[i]=rr.nextGaussian();
1050                     ran[i] = ran[i]*sd+mean;
1051                 }
1052                 return ran;
1053         }
1054 
1055         // Returns an array of Gaussian (normal) random deviates - clock seed
1056         // mean  =  the mean, sd = standard deviation, length of array
1057         public static double[] gaussianRand(double mean, double sd, int n){
1058                 double[] ran = new double[n];
1059                 Random rr = new Random();
1060                 for(int i=0; i<n; i++){
1061                     ran[i]=rr.nextGaussian();
1062                     ran[i] = ran[i]*sd+mean;
1063                 }
1064                 return ran;
1065         }
1066 
1067         // Returns an array of Gaussian (normal) random deviates - user provided seed
1068         // mean  =  the mean, sd = standard deviation, length of array
1069         public static double[] normalRand(double mean, double sd, int n, long seed){
1070                 double[] ran = new double[n];
1071                 Random rr = new Random(seed);
1072                 for(int i=0; i<n; i++){
1073                     ran[i]=rr.nextGaussian();
1074                     ran[i] = ran[i]*sd+mean;
1075                 }
1076                 return ran;
1077         }
1078 
1079         // Returns an array of Gaussian (normal) random deviates - user provided seed
1080         // mean  =  the mean, sd = standard deviation, length of array
1081         public static double[] gaussianRand(double mean, double sd, int n, long seed){
1082                 double[] ran = new double[n];
1083                 Random rr = new Random(seed);
1084                 for(int i=0; i<n; i++){
1085                     ran[i]=rr.nextGaussian();
1086                     ran[i] = ran[i]*sd+mean;
1087                 }
1088                 return ran;
1089         }
1090 
1091 
1092 
1093         // Logistic cumulative distribution function
1094         // probability that a variate will assume a value less than the upperlimit
1095         // mu  =  location parameter, beta = scale parameter
1096         public static double logisticProb(double mu, double beta, double upperlimit){
1097                 return 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta)));
1098         }
1099 
1100 
1101         // Logistic cumulative distribution function
1102         // probability that a variate will assume a value between the lower and  the upper limits
1103         // mu  =  location parameter, beta = scale parameter
1104         public static double logisticProb(double mu, double beta, double lowerlimit, double upperlimit){
1105                 double arg1 = 0.5D*(1.0D + Math.tanh((lowerlimit - mu)/(2.0D*beta)));
1106                 double arg2 = 0.5D*(1.0D + Math.tanh((upperlimit - mu)/(2.0D*beta)));
1107                 return arg2 - arg1;
1108         }
1109 
1110         // Logistic probability density function
1111         // mu  =  location parameter, beta = scale parameter
1112         public static double logistic(double mu, double beta, double x){
1113                 return Fmath.square(Fmath.sech((x - mu)/(2.0D*beta)))/(4.0D*beta);
1114         }
1115 
1116         // Returns an array of logistic distribution random deviates - clock seed
1117         // mu  =  location parameter, beta = scale parameter
1118         public static double[] logisticRand(double mu, double beta, int n){
1119                 double[] ran = new double[n];
1120                 Random rr = new Random();
1121                 for(int i=0; i<n; i++){
1122                     ran[i] = 2.0D*beta*Fmath.atanh(2.0D*rr.nextDouble() - 1.0D) + mu;
1123                 }
1124                 return ran;
1125         }
1126 
1127         // Returns an array of Gaussian (normal) random deviates - user provided seed
1128         // mean  =  the mean, sd = standard deviation, length of array
1129         public static double[] logisticRand(double mu, double beta, int n, long seed){
1130                 double[] ran = new double[n];
1131                 Random rr = new Random(seed);
1132                 for(int i=0; i<n; i++){
1133                     ran[i] = 2.0D*beta*Fmath.atanh(2.0D*rr.nextDouble() - 1.0D) + mu;
1134                 }
1135                 return ran;
1136         }
1137 
1138         // Logistic distribution mean
1139         public static double logisticMean(double mu){
1140                 return mu;
1141         }
1142 
1143 
1144         // Logistic distribution standard deviation
1145         public static double logisticStandDev(double beta){
1146                 return Math.sqrt(Fmath.square(Math.PI*beta)/3.0D);
1147         }
1148 
1149         // Logistic distribution mode
1150         public static double logisticMode(double mu){
1151                 return mu;
1152         }
1153 
1154         // Logistic distribution median
1155         public static double logisticMedian(double mu){
1156                 return mu;
1157         }
1158 
1159         // Lorentzian cumulative distribution function
1160         // probability that a variate will assume a value less than the upperlimit
1161         public static double lorentzianProb(double mu, double gamma, double upperlimit){
1162                 double arg = (upperlimit - mu)/(gamma/2.0D);
1163                 return (1.0D/Math.PI)*(Math.atan(arg)+Math.PI/2.0);
1164         }
1165 
1166         // Lorentzian cumulative distribution function
1167         // probability that a variate will assume a value between the lower and  the upper limits
1168         public static double lorentzianProb(double mu, double gamma, double lowerlimit, double upperlimit){
1169                 double arg1 = (upperlimit - mu)/(gamma/2.0D);
1170                 double arg2 = (lowerlimit - mu)/(gamma/2.0D);
1171                 return (1.0D/Math.PI)*(Math.atan(arg1)-Math.atan(arg2));
1172         }
1173 
1174         // Cumulative Poisson Probability Function
1175         // probability that a number of Poisson random events will occur between 0 and k (inclusive)
1176         // k is an integer greater than equal to 1
1177         // mean  = mean of the Poisson distribution
1178         public static double poissonProb(int k, double mean){
1179                 if(k<1)throw new IllegalArgumentException("k must be an integer greater than or equal to 1");
1180                 return Stat.incompleteGammaComplementary((double) k, mean);
1181         }
1182 
1183         // Poisson Probability Function
1184         // k is an integer greater than or equal to zero
1185         // mean  = mean of the Poisson distribution
1186         public static double poisson(int k, double mean){
1187                 if(k<0)throw new IllegalArgumentException("k must be an integer greater than or equal to 0");
1188                 return Math.pow(mean, k)*Math.exp(-mean)/Stat.factorial((double)k);
1189         }
1190 
1191         // Returns an array of Poisson random deviates - clock seed
1192         // mean  =  the mean,  n = length of array
1193         // follows the ideas of Numerical Recipes
1194         public static double[] poissonRand(double mean, int n){
1195 
1196                 Random rr = new Random();
1197                 double[] ran = poissonRandCalc(rr, mean, n);
1198                 return ran;
1199         }
1200 
1201         // Returns an array of Poisson random deviates - user provided seed
1202         // mean  =  the mean,  n = length of array
1203         // follows the ideas of Numerical Recipes
1204         public static double[] poissonRand(double mean, int n, long seed){
1205 
1206                 Random rr = new Random(seed);
1207                 double[] ran = poissonRandCalc(rr, mean, n);
1208                 return ran;
1209         }
1210 
1211         // Calculates and returns an array of Poisson random deviates
1212         private static double[] poissonRandCalc(Random rr, double mean, int n){
1213                 double[] ran = new double[n];
1214                 double oldm = -1.0D;
1215                 double expt = 0.0D;
1216                 double em = 0.0D;
1217                 double term = 0.0D;
1218                 double sq = 0.0D;
1219                 double lnMean = 0.0D;
1220                 double yDev = 0.0D;
1221 
1222                 if(mean < 12.0D){
1223                     for(int i=0; i<n; i++){
1224                         if(mean != oldm){
1225                             oldm = mean;
1226                             expt = Math.exp(-mean);
1227                         }
1228                         em = -1.0D;
1229                         term = 1.0D;
1230                         do{
1231                             ++em;
1232                             term *= rr.nextDouble();
1233                         }while(term>expt);
1234                         ran[i] = em;
1235                     }
1236                 }
1237                 else{
1238                     for(int i=0; i<n; i++){
1239                         if(mean != oldm){
1240                             oldm = mean;
1241                             sq = Math.sqrt(2.0D*mean);
1242                             lnMean = Math.log(mean);
1243                             expt = lnMean - Stat.logGamma(mean+1.0D);
1244                         }
1245                         do{
1246                             do{
1247                                 yDev = Math.tan(Math.PI*rr.nextDouble());
1248                                 em = sq*yDev+mean;
1249                             }while(em<0.0D);
1250                             em = Math.floor(em);
1251                             term = 0.9D*(1.0D+yDev*yDev)*Math.exp(em*lnMean - Stat.logGamma(em+1.0D)-expt);
1252                         }while(rr.nextDouble()>term);
1253                         ran[i] = em;
1254                     }
1255                 }
1256                 return ran;
1257         }
1258 
1259 
1260         // Chi-Square Probability Function
1261         // probability that an observed chi-square value for a correct model should be less than chiSquare
1262         // nu  =  the degrees of freedom
1263         public static double chiSquareProb(double chiSquare, int nu){
1264                 return Stat.incompleteGamma((double)nu/2.0D, chiSquare/2.0D);
1265         }
1266 
1267         // Chi-Square Statistic for Poisson distribution
1268         public static double chiSquare(double[] observed, double[] expected, double[] variance){
1269             int nObs = observed.length;
1270             int nExp = expected.length;
1271             int nVar = variance.length;
1272             if(nObs!=nExp)throw new IllegalArgumentException("observed array length does not equal the expected array length");
1273             if(nObs!=nVar)throw new IllegalArgumentException("observed array length does not equal the variance array length");
1274             double chi = 0.0D;
1275             for(int i=0; i<nObs; i++){
1276                 chi += Fmath.square(observed[i]-expected[i])/variance[i];
1277             }
1278             return chi;
1279         }
1280 
1281         // Chi-Square Statistic for Poisson distribution for frequency data
1282         // and Poisson distribution for each bin
1283         // double arguments
1284         public static double chiSquareFreq(double[] observedFreq, double[] expectedFreq){
1285             int nObs = observedFreq.length;
1286             int nExp = expectedFreq.length;
1287             if(nObs!=nExp)throw new IllegalArgumentException("observed array length does not equal the expected array length");
1288             double chi = 0.0D;
1289             for(int i=0; i<nObs; i++){
1290                 chi += Fmath.square(observedFreq[i]-expectedFreq[i])/expectedFreq[i];
1291             }
1292             return chi;
1293         }
1294 
1295         // Chi-Square Statistic for Poisson distribution for frequency data
1296         // and Poisson distribution for each bin
1297         // int arguments
1298         public static double chiSquareFreq(int[] observedFreq, int[] expectedFreq){
1299             int nObs = observedFreq.length;
1300             int nExp = expectedFreq.length;
1301             if(nObs!=nExp)throw new IllegalArgumentException("observed array length does not equal the expected array length");
1302             double[] observ = new double[nObs];
1303             double[] expect = new double[nObs];
1304             for(int i=0; i<nObs; i++){
1305                 observ[i] = (int)observedFreq[i];
1306                 expect[i] = (int)expectedFreq[i];
1307             }
1308 
1309             return chiSquareFreq(observ, expect);
1310         }
1311 
1312         // Returns the binomial cumulative probabilty
1313         public static double binomialProb(double p, int n, int k){
1314                 if(p<0.0D || p>1.0D)throw new IllegalArgumentException("\np must lie between 0 and 1");
1315                 if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero");
1316                 if(k>n)throw new IllegalArgumentException("\nk is greater than n");
1317                 return Stat.incompleteBeta(k, n-k+1, p);
1318         }
1319 
1320         // Returns a binomial mass probabilty function
1321         public static double binomial(double p, int n, int k){
1322                 if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero");
1323                 if(k>n)throw new IllegalArgumentException("\nk is greater than n");
1324                 return Math.floor(0.5D + Math.exp(Stat.logFactorial(n) - Stat.logFactorial(k) - Stat.logFactorial(n-k)))*Math.pow(p, k)*Math.pow(1.0D - p, n - k);
1325         }
1326 
1327         // Returns a binomial Coefficient as a double
1328         public static double binomialCoeff(int n, int k){
1329                 if(k<0 || n<0)throw new IllegalArgumentException("\nn and k must be greater than or equal to zero");
1330                 if(k>n)throw new IllegalArgumentException("\nk is greater than n");
1331                 return Math.floor(0.5D + Math.exp(Stat.logFactorial(n) - Stat.logFactorial(k) - Stat.logFactorial(n-k)));
1332         }
1333 
1334         // Returns an array of n Binomial pseudorandom deviates from a binomial
1335         //  distribution of nTrial trials each of probablity, prob,
1336         //  after 	bndlev 	Numerical Recipes in C - W.H. Press et al. (Cambridge)
1337         //		            2nd edition 1992 p295.
1338         public double[] binomialRand(double prob, int nTrials, int n){
1339 
1340             if(nTrials<n)throw new IllegalArgumentException("Number of deviates requested, " + n + ", must be less than the number of trials, " + nTrials);
1341             if(prob<0.0D || prob>1.0D)throw new IllegalArgumentException("The probablity provided, " + prob + ", must lie between 0 and 1)");
1342 
1343             double[] ran = new double[n];                   // array of deviates to be returned
1344             Random rr = new Random();                       // instance of Random
1345 
1346 	        double binomialDeviate = 0.0D;                  // the binomial deviate to be returned
1347 	        double deviateMean = 0.0D;                      // mean of deviate to be produced
1348 	        double testDeviate = 0.0D;                      // test deviate
1349 	        double workingProb = 0.0;                       // working value of the probability
1350 	        double logProb = 0.0;                           // working value of the probability
1351 	        double probOld = -1.0D;                         // previous value of the working probability
1352 	        double probC = -1.0D;                           // complementary value of the working probability
1353 	        double logProbC = -1.0D;                        // log of the complementary value of the working probability
1354 	        int nOld= -1;                                   // previous value of trials counter
1355 	        double enTrials = 0.0D;                         // (double) trials counter
1356 	        double oldGamma = 0.0D;                         // a previous log Gamma function value
1357 	        double tanW = 0.0D;                             // a working tangent
1358 	        double hold0 = 0.0D;                            // a working holding variable
1359 	        int jj;                                         // counter
1360 
1361             double probOriginalValue = prob;
1362             for(int i=0; i<n; i++){
1363                 prob = probOriginalValue;
1364 	            workingProb=(prob <= 0.5D ? prob : 1.0-prob);    // distribution invariant on swapping prob for 1 - prob
1365 	            deviateMean = nTrials*workingProb;
1366 
1367 	            if(nTrials < 25) {
1368 	                // if number of trials greater than 25 use direct method
1369 		            binomialDeviate=0.0D;
1370 		            for(jj=1;jj<=nTrials;jj++)if (rr.nextDouble() < workingProb) ++binomialDeviate;
1371 	            }
1372 	            else if(deviateMean < 1.0D) {
1373 	                // if fewer than 1 out of 25 events - Poisson approximation is accurate
1374 		            double expOfMean=Math.exp(-deviateMean);
1375 		            testDeviate=1.0D;
1376 		            for (jj=0;jj<=nTrials;jj++) {
1377 			            testDeviate *= rr.nextDouble();
1378 			            if (testDeviate < expOfMean) break;
1379 		            }
1380 		            binomialDeviate=(jj <= nTrials ? jj : nTrials);
1381 
1382 	            }
1383 	            else{
1384 	                // use rejection method
1385 		            if(nTrials != nOld) {
1386 		                // if nTrials has changed compute useful quantities
1387 			            enTrials = (double)nTrials;
1388 			            oldGamma = Stat.logGamma(enTrials + 1.0D);
1389 			            nOld = nTrials;
1390 		            }
1391 		            if(workingProb != probOld) {
1392 		                // if workingProb has changed compute useful quantities
1393                         probC = 1.0 - workingProb;
1394 			            logProb = Math.log(workingProb);
1395 			            logProbC = Math.log(probC);
1396 			            probOld = workingProb;
1397 		            }
1398 
1399 		            double sq = Math.sqrt(2.0*deviateMean*probC);
1400 		            do{
1401 			            do{
1402 				            double angle = Math.PI*rr.nextDouble();
1403 				            tanW = Math.tan(angle);
1404 				            hold0 = sq*tanW + deviateMean;
1405 			            }while(hold0 < 0.0D || hold0 >= (enTrials + 1.0D));   //rejection test
1406 			            hold0 = Math.floor(hold0);                              // integer value distribution
1407 			            testDeviate = 1.2D*sq*(1.0D + tanW*tanW)*Math.exp(oldGamma - Stat.logGamma(hold0 + 1.0D) - Stat.logGamma(enTrials - hold0 + 1.0D) + hold0*logProb + (enTrials - hold0)*logProbC);
1408 		            }while(rr.nextDouble() > testDeviate);                         // rejection test
1409 		            binomialDeviate=hold0;
1410 	            }
1411 
1412 	            if(workingProb != prob) binomialDeviate = nTrials - binomialDeviate;       // symmetry transformation
1413 
1414 	            ran[i] = binomialDeviate;
1415 	        }
1416 
1417 	        return ran;
1418         }
1419 
1420         // Returns the F-distribution probabilty for degrees of freedom df1, df2
1421         // F ratio provided
1422         public static double fTestProb(double fValue, int df1, int df2){
1423             double ddf1 = (double)df1;
1424             double ddf2 = (double)df2;
1425             double x = ddf2/(ddf2+ddf1*fValue);
1426             return Stat.incompleteBeta(df2/2.0D, df1/2.0D, x);
1427         }
1428 
1429         // Returns the F-distribution probabilty for degrees of freedom df1, df2
1430         // numerator and denominator variances provided
1431         public static double fTestProb(double var1, int df1, double var2, int df2){
1432             double fValue = var1/var2;
1433             double ddf1 = (double)df1;
1434             double ddf2 = (double)df2;
1435             double x = ddf2/(ddf2+ddf1*fValue);
1436             return Stat.incompleteBeta(df2/2.0D, df1/2.0D, x);
1437         }
1438 
1439         // Returns the F-test value corresponding to a F-distribution probabilty, fProb,
1440         //   for degrees of freedom df1, df2
1441         public static double fTestValueGivenFprob(double fProb, int df1, int df2){
1442 
1443             // Create an array F-test value array
1444             int fTestsNum = 100;    // length of array
1445             double[] fTestValues = new double[fTestsNum];
1446             fTestValues[0]=0.0001D;             // lowest array value
1447             fTestValues[fTestsNum-1]=10000.0D;  // highest array value
1448             // calculate array increment - log scale
1449             double diff = (Fmath.log10(fTestValues[fTestsNum-1])-Fmath.log10(fTestValues[0]))/(fTestsNum-1);
1450             // Fill array
1451             for(int i=1; i<fTestsNum-1; i++){
1452                 fTestValues[i] = Math.pow(10.0D,(Fmath.log10(fTestValues[i-1])+diff));
1453             }
1454 
1455             // calculate F test probability array corresponding to F-test value array
1456             double[] fTestProb = new double[fTestsNum];
1457             for(int i=0; i<fTestsNum; i++){
1458                 fTestProb[i] = Stat.fTestProb(fTestValues[i], df1, df2);
1459             }
1460 
1461             // calculate F-test value for provided probability
1462             // using bisection procedure
1463             double fTest0 = 0.0D;
1464             double fTest1 = 0.0D;
1465             double fTest2 = 0.0D;
1466 
1467             // find bracket for the F-test probabilities and calculate F-Test value from above arrays
1468             boolean test0 = true;
1469             boolean test1 = true;
1470             int i=0;
1471             int endTest=0;
1472             while(test0){
1473                 if(fProb==fTestProb[i]){
1474                     fTest0=fTestValues[i];
1475                     test0=false;
1476                     test1=false;
1477                 }
1478                 else{
1479                     if(fProb>fTestProb[i]){
1480                         test0=false;
1481                         if(i>0){
1482                             fTest1=fTestValues[i-1];
1483                             fTest2=fTestValues[i];
1484                             endTest=-1;
1485                         }
1486                         else{
1487                             fTest1=fTestValues[i]/10.0D;
1488                             fTest2=fTestValues[i];
1489                         }
1490                     }
1491                     else{
1492                         i++;
1493                         if(i>fTestsNum-1){
1494                             test0=false;
1495                             fTest1=fTestValues[i-1];
1496                             fTest2=10.0D*fTestValues[i-1];
1497                             endTest=1;
1498                         }
1499                     }
1500                 }
1501             }
1502 
1503             // call bisection method
1504             if(test1)fTest0=fTestBisect(fProb, fTest1, fTest2, df1, df2, endTest);
1505 
1506             return fTest0;
1507         }
1508 
1509         // Bisection procedure for calculating and F-test value corresponding
1510         //   to a given F-test probability
1511         private static double fTestBisect(double fProb, double fTestLow, double fTestHigh, int df1, int df2, int endTest){
1512 
1513             double funcLow = fProb - Stat.fTestProb(fTestLow, df1, df2);
1514             double funcHigh = fProb - Stat.fTestProb(fTestHigh, df1, df2);
1515             double fTestMid = 0.0D;
1516             double funcMid = 0.0;
1517             int nExtensions = 0;
1518             int nIter = 1000;           // iterations allowed
1519             double check = fProb*1e-6;  // tolerance for bisection
1520             boolean test0 = true;       // test for extending bracket
1521             boolean test1 = true;       // test for bisection procedure
1522             while(test0){
1523                 if(funcLow*funcHigh>0.0D){
1524                     if(endTest<0){
1525                         nExtensions++;
1526                         if(nExtensions>100){
1527                             System.out.println("Class: Stats\nMethod: fTestBisect\nProbability higher than range covered\nF-test value is less than "+fTestLow);
1528                             System.out.println("This value was returned");
1529                             fTestMid=fTestLow;
1530                             test0=false;
1531                             test1=false;
1532                         }
1533                         fTestLow /= 10.0D;
1534                         funcLow = fProb - Stat.fTestProb(fTestLow, df1, df2);
1535                     }
1536                     else{
1537                         nExtensions++;
1538                         if(nExtensions>100){
1539                             System.out.println("Class: Stats\nMethod: fTestBisect\nProbability lower than range covered\nF-test value is greater than "+fTestHigh);
1540                             System.out.println("This value was returned");
1541                             fTestMid=fTestHigh;
1542                             test0=false;
1543                             test1=false;
1544                         }
1545                         fTestHigh *= 10.0D;
1546                         funcHigh = fProb - Stat.fTestProb(fTestHigh, df1, df2);
1547                     }
1548                 }
1549                 else{
1550                     test0=false;
1551                 }
1552 
1553                 int i=0;
1554                 while(test1){
1555                     fTestMid = (fTestLow+fTestHigh)/2.0D;
1556                     funcMid = fProb - Stat.fTestProb(fTestMid, df1, df2);
1557                     if(Math.abs(funcMid)<check){
1558                         test1=false;
1559                     }
1560                     else{
1561                         i++;
1562                         if(i>nIter){
1563                             System.out.println("Class: Stats\nMethod: fTestBisect\nmaximum number of iterations exceeded\ncurrent value of F-test value returned");
1564                             test1=false;
1565                         }
1566                         if(funcMid*funcHigh>0){
1567                             funcHigh=funcMid;
1568                             fTestHigh=fTestMid;
1569                         }
1570                         else{
1571                             funcLow=funcMid;
1572                             fTestLow=fTestMid;
1573                         }
1574                     }
1575                 }
1576             }
1577             return fTestMid;
1578         }
1579 
1580         // Returns the Student t probability density function
1581         public static double studentT(double tValue, int df){
1582             double ddf = (double)df;
1583             double dfterm = (ddf + 1.0D)/2.0D;
1584             return ((Stat.gamma(dfterm)/Stat.gamma(ddf/2))/Math.sqrt(ddf*Math.PI))*Math.pow(1.0D + tValue*tValue/ddf, -dfterm);
1585         }
1586 
1587         // Returns the Student t cumulative distribution function probability
1588         public static double studentTProb(double tValue, int df){
1589             double ddf = (double)df;
1590             double x = ddf/(ddf+tValue*tValue);
1591             return 0.5D*(1.0D + (Stat.incompleteBeta(ddf/2.0D, 0.5D, 1) - Stat.incompleteBeta(ddf/2.0D, 0.5D, x))*Fmath.sign(tValue));
1592         }
1593 
1594         // Returns the A(t|n) distribution probabilty
1595         public static double probAtn(double tValue, int df){
1596             double ddf = (double)df;
1597             double x = ddf/(ddf+tValue*tValue);
1598             return 1.0D - Stat.incompleteBeta(ddf/2.0D, 0.5D, x);
1599         }
1600 
1601         // Distribute data into bins to obtain histogram
1602         // zero bin position and upper limit provided
1603         public static double[][] histogramBins(double[] data, double binWidth, double binZero, double binUpper){
1604             int n = 0;              // new array length
1605             int m = data.length;    // old array length;
1606             for(int i=0; i<m; i++)if(data[i]<=binUpper)n++;
1607             if(n!=m){
1608                 double[] newData = new double[n];
1609                 int j = 0;
1610                 for(int i=0; i<m; i++){
1611                     if(data[i]<=binUpper){
1612                         newData[j] = data[i];
1613                         j++;
1614                     }
1615                 }
1616                 System.out.println((m-n)+" data points, above histogram upper limit, excluded in Stat.histogramBins");
1617                 return histogramBins(newData, binWidth, binZero);
1618             }
1619             else{
1620                  return histogramBins(data, binWidth, binZero);
1621 
1622             }
1623         }
1624 
1625         // Distribute data into bins to obtain histogram
1626         // zero bin position provided
1627         public static double[][] histogramBins(double[] data, double binWidth, double binZero){
1628             double dmax = Fmath.maximum(data);
1629             int nBins = (int) Math.ceil((dmax - binZero)/binWidth);
1630             if(binZero+nBins*binWidth>dmax)nBins++;
1631             int nPoints = data.length;
1632             int[] dataCheck = new int[nPoints];
1633             for(int i=0; i<nPoints; i++)dataCheck[i]=0;
1634             double[]binWall = new double[nBins+1];
1635             binWall[0]=binZero;
1636             for(int i=1; i<=nBins; i++){
1637                 binWall[i] = binWall[i-1] + binWidth;
1638             }
1639             double[][] binFreq = new double[2][nBins];
1640             for(int i=0; i<nBins; i++){
1641                 binFreq[0][i]= (binWall[i]+binWall[i+1])/2.0D;
1642                 binFreq[1][i]= 0.0D;
1643             }
1644             boolean test = true;
1645 
1646             for(int i=0; i<nPoints; i++){
1647                 test=true;
1648                 int j=0;
1649                 while(test){
1650                     if(j==nBins-1){
1651                         if(data[i]>=binWall[j] && data[i]<=binWall[j+1]*(1.0D + Stat.histTol)){
1652                             binFreq[1][j]+= 1.0D;
1653                             dataCheck[i]=1;
1654                             test=false;
1655                         }
1656                     }
1657                     else{
1658                         if(data[i]>=binWall[j] && data[i]<binWall[j+1]){
1659                             binFreq[1][j]+= 1.0D;
1660                             dataCheck[i]=1;
1661                             test=false;
1662                         }
1663                     }
1664                     if(test){
1665                         if(j==nBins-1){
1666                             test=false;
1667                         }
1668                         else{
1669                             j++;
1670                         }
1671                     }
1672                 }
1673             }
1674             int nMissed=0;
1675             for(int i=0; i<nPoints; i++)if(dataCheck[i]==0){
1676                 nMissed++;
1677                 System.out.println("p " + i + " " + data[i] + " " + binWall[0] + " " + binWall[nBins]);
1678             }
1679             if(nMissed>0)System.out.println(nMissed+" data points, outside histogram limits, excluded in Stat.histogramBins");
1680             return binFreq;
1681         }
1682 
1683         // Distribute data into bins to obtain histogram
1684         // zero bin position calculated
1685         public static double[][] histogramBins(double[] data, double binWidth){
1686 
1687             double dmin = Fmath.minimum(data);
1688             double dmax = Fmath.maximum(data);
1689             double span = dmax - dmin;
1690             double binZero = dmin;
1691             int nBins = (int) Math.ceil(span/binWidth);
1692             double histoSpan = ((double)nBins)*binWidth;
1693             double rem = histoSpan - span;
1694             if(rem>=0){
1695                 binZero -= rem/2.0D;
1696             }
1697             else{
1698                 if(Math.abs(rem)/span>histTol){
1699                     // readjust binWidth
1700                     boolean testBw = true;
1701                     double incr = histTol/nBins;
1702                     int iTest = 0;
1703                     while(testBw){
1704                        binWidth += incr;
1705                        histoSpan = ((double)nBins)*binWidth;
1706                         rem = histoSpan - span;
1707                         if(rem<0){
1708                             iTest++;
1709                             if(iTest>1000){
1710                                 testBw = false;
1711                                 System.out.println("histogram method could not encompass all data within histogram\nContact Michael thomas Flanagan");
1712                             }
1713                         }
1714                         else{
1715                             testBw = false;
1716                         }
1717                     }
1718                 }
1719             }
1720 
1721             return Stat.histogramBins(data, binWidth, binZero);
1722         }
1723 
1724         // factorial of n
1725         // argument and return are integer, therefore limited to 0<=n<=12
1726         // see below for long and double arguments
1727         public static int factorial(int n){
1728                 if(n<0)throw new IllegalArgumentException("n must be a positive integer");
1729                 if(n>12)throw new IllegalArgumentException("n must less than 13 to avoid integer overflow\nTry long or double argument");
1730                 int f = 1;
1731                 for(int i=1; i<=n; i++)f*=i;
1732                 return f;
1733         }
1734 
1735         // factorial of n
1736         // argument and return are long, therefore limited to 0<=n<=20
1737         // see below for double argument
1738         public static long factorial(long n){
1739                 if(n<0)throw new IllegalArgumentException("n must be a positive integer");
1740                 if(n>20)throw new IllegalArgumentException("n must less than 21 to avoid long integer overflow\nTry double argument");
1741                 long f = 1;
1742                 for(int i=1; i<=n; i++)f*=i;
1743                 return f;
1744         }
1745 
1746         // factorial of n
1747         // Argument is of type double but must be, numerically, an integer
1748         // factorial returned as double but is, numerically, should be an integer
1749         // numerical rounding may makes this an approximation after n = 21
1750         public static double factorial(double n){
1751                 if(n<0 || (n-(int)n)!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
1752                 double f = 1.0D;
1753                 int nn = (int)n;
1754                 for(int i=1; i<=nn; i++)f*=i;
1755                 return f;
1756         }
1757 
1758         // log to base e of the factorial of n
1759         // log[e](factorial) returned as double
1760         // numerical rounding may makes this an approximation
1761         public static double logFactorial(int n){
1762                 if(n<0 || (n-(int)n)!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
1763                 double f = 0.0D;
1764                 for(int i=2; i<=n; i++)f+=Math.log(i);
1765                 return f;
1766         }
1767 
1768         // log to base e of the factorial of n
1769         // Argument is of type double but must be, numerically, an integer
1770         // log[e](factorial) returned as double
1771         // numerical rounding may makes this an approximation
1772         public static double logFactorial(double n){
1773         if(n<0 || (n-(int)n)!=0)throw new IllegalArgumentException("\nn must be a positive integer\nIs a Gamma funtion [Fmath.gamma(x)] more appropriate?");
1774                 double f = 0.0D;
1775                 int nn = (int)n;
1776                 for(int i=2; i<=nn; i++)f+=Math.log(i);
1777                 return f;
1778         }
1779 
1780         // Calculate correlation coefficient
1781         // x y data as double
1782         public static double corrCoeff(double[] xx, double[]yy){
1783 
1784             double temp0 = 0.0D, temp1 = 0.0D;  // working variables
1785             int nData = xx.length;
1786             if(yy.length!=nData)throw new IllegalArgumentException("array lengths must be equal");
1787             int df = nData-1;
1788             // means
1789             double mx = 0.0D;
1790             double my = 0.0D;
1791             for(int i=0; i<nData; i++){
1792                 mx += xx[i];
1793                 my += yy[i];
1794             }
1795             mx /= nData;
1796             my /= nData;
1797 
1798             // calculate sample variances
1799             double s2xx = 0.0D;
1800             double s2yy = 0.0D;
1801             double s2xy = 0.0D;
1802             for(int i=0; i<nData; i++){
1803                 s2xx += Fmath.square(xx[i]-mx);
1804                 s2yy += Fmath.square(yy[i]-my);
1805                 s2xy += (xx[i]-mx)*(yy[i]-my);
1806             }
1807             s2xx /= df;
1808             s2yy /= df;
1809             s2xy /= df;
1810 
1811             // calculate corelation coefficient
1812             double sampleR = s2xy/Math.sqrt(s2xx*s2yy);
1813 
1814             return sampleR;
1815         }
1816 
1817         // Calculate correlation coefficient
1818         // x y data as float
1819         public static float corrCoeff(float[] x, float[] y){
1820             int nData = x.length;
1821             if(y.length!=nData)throw new IllegalArgumentException("array lengths must be equal");
1822             int n = x.length;
1823             double[] xx = new double[n];
1824             double[] yy = new double[n];
1825             for(int i=0; i<n; i++){
1826                 xx[i] = (double)x[i];
1827                 yy[i] = (double)y[i];
1828             }
1829             return (float)Stat.corrCoeff(xx, yy);
1830         }
1831 
1832         // Calculate correlation coefficient
1833         // x y data as int
1834         public static double corrCoeff(int[] x, int[]y){
1835             int n = x.length;
1836             if(y.length!=n)throw new IllegalArgumentException("array lengths must be equal");
1837 
1838             double[] xx = new double[n];
1839             double[] yy = new double[n];
1840             for(int i=0; i<n; i++){
1841                 xx[i] = (double)x[i];
1842                 yy[i] = (double)y[i];
1843             }
1844             return Stat.corrCoeff(xx, yy);
1845         }
1846 
1847         // Calculate weighted correlation coefficient
1848         // x y data and weights w as double
1849         public static double corrCoeff(double[] x, double[]y, double[] w){
1850             int n = x.length;
1851             if(y.length!=n)throw new IllegalArgumentException("x and y array lengths must be equal");
1852             if(w.length!=n)throw new IllegalArgumentException("x and weight array lengths must be equal");
1853 
1854             double sxy = Stat.covariance(x, y, w);
1855             double sx = Stat.variance(x, w);
1856             double sy = Stat.variance(y, w);
1857             return sxy/Math.sqrt(sx*sy);
1858         }
1859 
1860         // Calculate correlation coefficient
1861         // Binary data x and y
1862         // Input is the frequency matrix, F, elements, f(i,j)
1863         // f(0,0) - element00 - frequency of x and y both = 1
1864         // f(0,1) - element01 - frequency of x = 0 and y = 1
1865         // f(1,0) - element10 - frequency of x = 1 and y = 0
1866         // f(1,1) - element11 - frequency of x and y both = 0
1867         public static double corrCoeff(int element00, int element01, int element10, int element11){
1868             return ((double)(element00*element11 - element01*element10))/Math.sqrt((double)((element00+element01)*(element10+element11)*(element00+element10)*(element01+element11)));
1869         }
1870 
1871         // Calculate correlation coefficient
1872         // Binary data x and y
1873         // Input is the frequency matrix, F
1874         // F(0,0) - frequency of x and y both = 1
1875         // F(0,1) - frequency of x = 0 and y = 1
1876         // F(1,0) - frequency of x = 1 and y = 0
1877         // F(1,1) - frequency of x and y both = 0
1878         public static double corrCoeff(int[][] freqMatrix){
1879             double element00 = (double)freqMatrix[0][0];
1880             double element01 = (double)freqMatrix[0][1];
1881             double element10 = (double)freqMatrix[1][0];
1882             double element11 = (double)freqMatrix[1][1];
1883             return ((element00*element11 - element01*element10))/Math.sqrt(((element00+element01)*(element10+element11)*(element00+element10)*(element01+element11)));
1884         }
1885 
1886         // Linear correlation coefficient single probablity
1887         // old name calls renamed method
1888         public static double linearCorrCoeff(double rCoeff, int nu){
1889             return Stat.corrCoeffPdf(rCoeff, nu);
1890         }
1891 
1892         // Linear correlation coefficient single probablity
1893         public static double corrCoeffPdf(double rCoeff, int nu){
1894             if(Math.abs(rCoeff)>1.0D)throw new IllegalArgumentException("|Correlation coefficient| > 1 :  " + rCoeff);
1895 
1896             double a = ((double)nu - 2.0D)/2.0D;
1897             double y = Math.pow((1.0D - Fmath.square(rCoeff)),a);
1898 
1899             double preterm = Math.exp(Stat.logGamma((nu+1.0D)/2.0)-Stat.logGamma(nu/2.0D))/Math.sqrt(Math.PI);
1900 
1901             return preterm*y;
1902         }
1903 
1904         // Weibull cumulative distribution function
1905         // probability that a variate will assume  a value less than the upperlimit
1906         public static double weibullProb(double mu, double sigma, double gamma, double upperlimit){
1907                 double arg = (upperlimit - mu)/sigma;
1908                 double y = 0.0D;
1909                 if(arg>0.0D)y = 1.0D - Math.exp(-Math.pow(arg, gamma));
1910                 return y;
1911         }
1912 
1913         // Weibull cumulative distribution function
1914         // probability that a variate will assume a value between the lower and  the upper limits
1915         public static double weibullProb(double mu, double sigma, double gamma, double lowerlimit, double upperlimit){
1916                 double arg1 = (lowerlimit - mu)/sigma;
1917                 double arg2 = (upperlimit - mu)/sigma;
1918                 double term1 = 0.0D, term2 = 0.0D;
1919                 if(arg1>=0.0D)term1 = -Math.exp(-Math.pow(arg1, gamma));
1920                 if(arg2>=0.0D)term2 = -Math.exp(-Math.pow(arg2, gamma));
1921                 return term2-term1;
1922         }
1923 
1924         // Weibull probability
1925         public static double weibull(double mu,double sigma, double gamma, double x){
1926                 double arg =(x-mu)/sigma;
1927                 double y = 0.0D;
1928                 if(arg>=0.0D){
1929                     y = (gamma/sigma)*Math.pow(arg, gamma-1.0D)*Math.exp(-Math.pow(arg, gamma));
1930                 }
1931                 return y;
1932         }
1933 
1934         // Weibull mean
1935         public static double weibullMean(double mu,double sigma, double gamma){
1936                 return mu + sigma*Stat.gamma(1.0D/gamma+1.0D);
1937         }
1938 
1939         // Weibull standard deviation
1940         public static double weibullStandDev(double sigma, double gamma){
1941                 double y = Stat.gamma(2.0D/gamma+1.0D)-Fmath.square(Stat.gamma(1.0D/gamma+1.0D));
1942                 return sigma*Math.sqrt(y);
1943         }
1944 
1945         // Weibull mode
1946         public static double weibullMode(double mu,double sigma, double gamma){
1947             double y=mu;
1948             if(gamma>1.0D){
1949                 y = mu + sigma*Math.pow((gamma-1.0D)/gamma, 1.0D/gamma);
1950             }
1951             return y;
1952         }
1953 
1954         // Weibull median
1955         public static double weibullMedian(double mu,double sigma, double gamma){
1956             return mu + sigma*Math.pow(Math.log(2.0D),1.0D/gamma);
1957         }
1958 
1959         // Returns an array of Weibull (Type III EVD) random deviates - clock seed
1960         // mu  =  location parameter, sigma = cale parameter, gamma = shape parametern = length of array
1961         public static double[] weibullRand(double mu, double sigma, double gamma, int n){
1962                 double[] ran = new double[n];
1963                 Random rr = new Random();
1964                 for(int i=0; i<n; i++){
1965                      ran[i] = Math.pow(-Math.log(1.0D-rr.nextDouble()),1.0D/gamma)*sigma + mu;
1966                 }
1967                 return ran;
1968         }
1969 
1970         // Returns an array of Weibull (Type III EVD) random deviates - user supplied seed
1971         // mu  =  location parameter, sigma = cale parameter, gamma = shape parametern = length of array
1972         public static double[] weibullRand(double mu, double sigma, double gamma, int n, long seed){
1973                 double[] ran = new double[n];
1974                 Random rr = new Random(seed);
1975                 for(int i=0; i<n; i++){
1976                      ran[i] = Math.pow(-Math.log(1.0D-rr.nextDouble()),1.0D/gamma)*sigma + mu;
1977                 }
1978                 return ran;
1979         }
1980 
1981         // Frechet cumulative distribution function
1982         // probability that a variate will assume  a value less than the upperlimit
1983         public static double frechetProb(double mu, double sigma, double gamma, double upperlimit){
1984                 double arg = (upperlimit - mu)/sigma;
1985                 double y = 0.0D;
1986                 if(arg>0.0D)y = Math.exp(-Math.pow(arg, -gamma));
1987                 return y;
1988         }
1989 
1990 
1991         // Frechet cumulative distribution function
1992         // probability that a variate will assume a value between the lower and  the upper limits
1993         public static double frechetProb(double mu, double sigma, double gamma, double lowerlimit, double upperlimit){
1994                 double arg1 = (lowerlimit - mu)/sigma;
1995                 double arg2 = (upperlimit - mu)/sigma;
1996                 double term1 = 0.0D, term2 = 0.0D;
1997                 if(arg1>=0.0D)term1 = Math.exp(-Math.pow(arg1, -gamma));
1998                 if(arg2>=0.0D)term2 = Math.exp(-Math.pow(arg2, -gamma));
1999                 return term2-term1;
2000         }
2001 
2002         // Exponential cumulative distribution function
2003         // probability that a variate will assume  a value less than the upperlimit
2004         public static double exponentialProb(double mu, double sigma, double upperlimit){
2005                 double arg = (upperlimit - mu)/sigma;
2006                 double y = 0.0D;
2007                 if(arg>0.0D)y = 1.0D - Math.exp(-arg);
2008                 return y;
2009         }
2010 
2011         // Exponential cumulative distribution function
2012         // probability that a variate will assume a value between the lower and  the upper limits
2013         public static double exponentialProb(double mu, double sigma, double lowerlimit, double upperlimit){
2014                 double arg1 = (lowerlimit - mu)/sigma;
2015                 double arg2 = (upperlimit - mu)/sigma;
2016                 double term1 = 0.0D, term2 = 0.0D;
2017                 if(arg1>=0.0D)term1 = -Math.exp(-arg1);
2018                 if(arg2>=0.0D)term2 = -Math.exp(-arg2);
2019                 return term2-term1;
2020         }
2021 
2022         // Exponential probability
2023         public static double exponential(double mu,double sigma, double x){
2024                 double arg =(x-mu)/sigma;
2025                 double y = 0.0D;
2026                 if(arg>=0.0D){
2027                     y = Math.exp(-arg)/sigma;
2028                 }
2029                 return y;
2030         }
2031 
2032         // Exponential mean
2033         public static double exponentialMean(double mu, double sigma){
2034                 return mu + sigma;
2035         }
2036 
2037         // Exponential standard deviation
2038         public static double exponentialStandDev(double sigma){
2039                 return sigma;
2040         }
2041 
2042         // Exponential mode
2043         public static double exponentialMode(double mu){
2044             return mu;
2045         }
2046 
2047         // Exponential median
2048         public static double exponentialMedian(double mu,double sigma){
2049             return mu + sigma*Math.log(2.0D);
2050         }
2051 
2052         // Returns an array of Exponential random deviates - clock seed
2053         // mu  =  location parameter, sigma = cale parameter, gamma = shape parametern = length of array
2054         public static double[] exponentialRand(double mu, double sigma, int n){
2055                 double[] ran = new double[n];
2056                 Random rr = new Random();
2057                 for(int i=0; i<n; i++){
2058                      ran[i] = mu - Math.log(1.0D-rr.nextDouble())*sigma;
2059                 }
2060                 return ran;
2061         }
2062 
2063         // Returns an array of Exponential random deviates - user supplied seed
2064         // mu  =  location parameter, sigma = cale parameter, gamma = shape parametern = length of array
2065         public static double[] exponentialRand(double mu, double sigma, int n, long seed){
2066                 double[] ran = new double[n];
2067                 Random rr = new Random(seed);
2068                 for(int i=0; i<n; i++){
2069                      ran[i] = mu - Math.log(1.0D-rr.nextDouble())*sigma;
2070                 }
2071                 return ran;
2072         }
2073  }