//The Fisher exact test for a 2*5 or smaller crosstable.
//copyright: Daan G Uitenbroek PhD

function cut(real,lenght)  // changes scientific into normal notation and makes to size
{
var str=""+real;
var r="0.";
var pt=str.indexOf("e");
if (pt>0 ) 
    {
     var a=str.substring(0,1)+str.substring(2,pt+1);
     for (var index=1;index<=(str.substring(pt+2,pt+5)*1-1);index++)
        r+=0;
     var st=r+a;
      for (var index=st.length;index<=lenght;index++)
         st+="0";
     return (st.substring(0,lenght));
     };
for (var index=str.length;index<=lenght;index++)
      str+="0";
pt=str.indexOf(".");
if (pt==0) str="0"+str           //solves that newer versions of Netscape give inconsistent numeric notations
return str.substring(0,lenght);
}

function truncate(real,places)  // truncates 'real' numbers n 'places' behind the decimal dot
{
var multi=Math.pow(10,places);
return (Math.round(real*multi)/multi)
}

function odd(number)    //returns zero if number is not odd, one if it is
{
var isodd=0*1;
if (Math.round(number/2+0.00001)==number/2)  isodd=1*1;
return isodd
}

function c2prob(chi2,df)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

var add=0;
var mult=1;
if (odd(df)<0.5)
 {
      add=1;
      mult=Math.sqrt(2/chi2/Math.PI);
   }
var denominator=1;
for (var index=df;index>1;index-=2)
         denominator=denominator*index;
var numerator=Math.pow(chi2,((df*1+add*1)/2))*Math.exp(chi2*-1/2);
sum=1*1;
m=1*1;

for (var count=df*1+2*1;m>0.00000000001;count+=2)
   {
      m=(m*chi2)/count;
      sum=sum*1+m*1;
   }
var pval=1-sum*mult*numerator/denominator
return pval
}

function odt(len1)   // to create a onedimensional table
{
  this.lenght=len1;
   for (var i=1;i<=len1;i++)
      this[i]=0;
  return this
}

function table(len1,len2)   // to create a two dimensional table
{
   this.lenght=len1;
      for (var j=1;j<=len1;j++)
           this[j]=new odt(len2);
    return this
}

function printtable(table)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

for (var index=1;index<=4;index++)
   {
   for (var jndex=1;jndex<=3;jndex++)
      document.form1.outp.value+=table[index][jndex]+"  "
   document.form1.outp.value+=writeln
   }
document.form1.outp.value+=writeln
}

function probtab(table,con)
{
var pointprob=0
for (var index=1;index<=5;index++)
 for (var jndex=1;jndex<=2;jndex++)
   pointprob=pointprob+factors[table[index][jndex]+1*1]*1
pointprob=Math.exp(con-pointprob)
return pointprob
}

function threeby2(n11,n12,n21,n22,n31,n32,n41,n42,n51,n52,checkbox)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

data=new table(6,3);
data[1][1]=n11/1;
data[1][2]=n12/1;
data[2][1]=n21/1;
data[2][2]=n22/1;
data[3][1]=n31/1;
data[3][2]=n32/1;
data[4][1]=n41/1;
data[4][2]=n42/1;
data[5][1]=n51/1;
data[5][2]=n52/1;

data[1][3]=data[1][1]+data[1][2]*1;
data[2][3]=data[2][1]+data[2][2]*1;
data[3][3]=data[3][1]+data[3][2]*1;
data[4][3]=data[4][1]+data[4][2]*1;
data[5][3]=data[5][1]+data[5][2]*1;
data[6][1]=data[1][1]+data[2][1]*1+data[3][1]*1+data[4][1]*1+data[5][1]*1;
data[6][2]=data[1][2]+data[2][2]*1+data[3][2]*1+data[4][2]*1+data[5][2]*1;     // make marginals
data[6][3]=data[6][1]+data[6][2]*1     //total in  5,3

data2=new table(6,3)
data2[1][1]=n11/1;
data2[1][2]=n12/1;
data2[2][1]=n21/1;
data2[2][2]=n22/1;
data2[3][1]=n31/1;
data2[3][2]=n32/1;
data2[4][1]=n41/1;
data2[4][2]=n42/1;
data2[5][1]=n51/1;
data2[5][2]=n52/1;

data2[1][3]=data[1][1]+data[1][2]*1;
data2[2][3]=data[2][1]+data[2][2]*1;
data2[3][3]=data[3][1]+data[3][2]*1;
data2[4][3]=data[4][1]+data[4][2]*1;
data2[5][3]=data[5][1]+data[5][2]*1;
data2[6][1]=data[1][1]+data[2][1]*1+data[3][1]*1+data[4][1]*1+data[5][1]*1;
data2[6][2]=data[1][2]+data[2][2]*1+data[3][2]*1+data[4][2]*1+data[5][2]*1;     // make marginals
data2[6][3]=data[6][1]+data[6][2]*1     //total in  5,3

//printtable(data)

if (data[6][1]>data[6][2])
for (var index=1;index<=6.0002;index++)
    {var help=data[index][1]
     data[index][1]=data[index][2]
     data[index][2]=help}  //swap smallest number collumn marginal to the left

var hulp=new odt(3)
for (var index=1;index<=4;index++)
 for (var jndex=index;jndex<=5;jndex++)
if (data[index][3]>data[jndex][3])  
{var hulp=data[index]
 data[index]=data[jndex]
 data[jndex]=hulp
}     //bubble smallest marginal to the top

//printtable(data)

factors=new odt(data[6][3]+1*1); 
factors[1]=0; 
factors[2]=0; 
for (var i=1;i<(data[6][3]+2*1);i++)   
factors[i+1]=factors[i]+Math.log(i); //make an array of log factorials

constant=factors[data[1][3]+1*1]+factors[data[2][3]+1*1]*1+factors[data[3][3]+1*1]*1
constant=constant+factors[data[4][3]+1*1]*1+factors[data[5][3]+1*1]*1
constant=constant+factors[data[6][1]+1*1]*1+factors[data[6][2]+1*1]*1-factors[data[6][3]+1*1]

var pointpr=probtab(data,constant)
document.form1.outp.value+="the pointprobability eq: "+pointpr+writeln+writeln 

duble2=0;
duble=0;
noftables=0*1

if (checkbox.checked)
{
roworcol=data[1][3];
if (roworcol>data[6][1]) roworcol=data[6][1]
colrow=data[2][3];
if (colrow>data[6][1]) colrow=data[6][1]
rowcol=data[3][3];
if (rowcol>data[6][1]) rowcol=data[6][1]

for (var index=0;index<=roworcol;index++)
{data[1][1]=index
 data[1][2]=data[1][3]-index

 for (var kndex=0;kndex<=colrow;kndex++)
  {data[2][1]=kndex
   data[2][2]=data[2][3]-kndex

   for (var lndex=0;lndex<=rowcol;lndex++)
    {data[3][1]=lndex
     data[3][2]=data[3][3]-lndex

     var colorrow=data[6][1]-index-kndex-lndex;  
     if (colorrow>data[4][3]) colorrow=data[4][3]
     var start=0
     if (data[5][3]<(data[6][1]-index-kndex-lndex)) 
         start=data[6][1]-data[5][3]-index-kndex-lndex
 
      for (var jndex=start;jndex<=colorrow;jndex++)
       {data[4][1]=jndex
        data[4][2]=data[4][3]-jndex
        data[5][1]=data[6][1]-index-kndex-lndex-jndex
        data[5][2]=data[5][3]-data[5][1]
        noftables++
        probability=probtab(data,constant)
        if (probability<=(pointpr+1.0e-15*1))
          duble=duble+probability*1
        if (probability<pointpr)
          duble2=duble2+probability*1
        //printtable(data)
       } 
    }
   }
} //produce all permutations of the table


document.form1.outp.value+="Two sided p-value for p(O>=E|O<=E) "+writeln+"  p-value= "
                         +cut(duble,12)+" (the sum of small p's)"+writeln
document.form1.outp.value+="Two sided p-value for p(O>E|O<E) "+writeln+"  p-value= "
                         +cut(duble2,12)+" (the sum of small p's)"+writeln
document.form1.outp.value+="Two sided p-value mid-p"+writeln+"  p-value= "
                         +cut(duble/2+duble2/2,12)+" (the sum of small p's)"+writeln
document.form1.outp.value+=writeln+noftables+" tables evaluated"+writeln
}

exptable=new table(5,2)

for (var index=1;index<6;index++) 
 for (var jndex=1;jndex<3;jndex++)    
  exptable[index][jndex]=data2[index][3]*data2[6][jndex]/data2[6][3]

var chi2a=1*0;
var chi2=1*0;
var lrx=1*0;

emptyrow=0*1;
for (var index=1;index<6;index++) 
 for (var jndex=1;jndex<3;jndex++)
   if ((data2[index][3]>0)&&(data2[6][jndex]>0))        
    chi2a=chi2a+(((data2[index][jndex]*data2[index][jndex])*1
            -(exptable[index][jndex]*exptable[index][jndex]))/exptable[index][jndex]);
   else (emptyrow+=0.5)

var emptycell=0
for (var index=1;index<6;index++) 
 for (var jndex=1;jndex<3;jndex++)
  if (data2[index][jndex]>0)    
{chi2=chi2+(((data2[index][jndex]*data2[index][jndex])*1
            -(exptable[index][jndex]*exptable[index][jndex]))/exptable[index][jndex]);
   lrx=lrx+(data2[index][jndex]*(Math.log(data2[index][jndex])
            -Math.log(exptable[index][jndex])));
}
else if ((data2[index][3]!=0)&&(data2[6][jndex]!=0)) emptycell=1 
lrx=lrx*2;

if (emptycell==1)
  {document.form1.outp.value+=writeln+"Chi square (with "+(4-emptyrow)+" degrees of freedom):"+writeln
   document.form1.outp.value+="    (including empty -zero- cell)"+writeln
   document.form1.outp.value+="  Pearson's= "+truncate(chi2a,3)+" (p= "+cut(c2prob(chi2a,(4-emptyrow)),6)+")"+writeln}

document.form1.outp.value+=writeln+"Chi squares (both with "+(4-emptyrow)+" degree of freedom):"+writeln
if (emptycell==1)
  document.form1.outp.value+="    (excluding empty -zero- cell)"+writeln
document.form1.outp.value+="  Pearson's= "+truncate(chi2,3)+" (p= "+cut(c2prob(chi2,(4-emptyrow)),6)+")"+writeln+
         "  Likelihood Ratio= "+truncate(lrx,3)+" (p= "+cut(c2prob(lrx,(4-emptyrow)),6)+")"+writeln

document.form1.outp.value+=writeln
}

function ClearOutp()
{
var writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n"; 

document.form1.outp.value="cleared; "+writeln;
}

