//Tests for ordinal series online. Including Man-Whitney, Wald-
//Wolfowitz, Wilcoxon, Kolmogorov Smirnov and test for randomness.
//copyright: Daan G Uitenbroek PhD

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 cut(real,lenght)  // changes scientific into normal notation and cuts 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 zpr(zval)  
{
outp=1
if ((zval<5)&(zval>-5))    //Math.abs doesn't work in an if statement 
{
if (zval == 0.0)     
     var x  = 0.0;        
else      
     {  
     var y = 0.5 * Math.abs (zval);        
     if (y >= (10000* 0.5))        
             x=1.0;  
     else if (y < 1.0)         
     {         
     var w = y*y;          
     x = ((((((((0.000124818987 * w  
          -0.001075204047) * w +0.005198775019) * w  
          -0.019198292004) * w +0.059054035642) * w  
          -0.151968751364) * w +0.319152932694) * w  
          -0.531923007300) * w +0.797884560593) * y * 2.0;     
    
     }         
     else      
     {  
     y -= 2.0;         
     x  = (((((((((((((-0.000045255659 * y  
          +0.000152529290) * y -0.000019538132) * y  
          -0.000676904986) * y +0.001390604284) * y  
          -0.000794620820) * y -0.002034254874) * y  
          +0.006549791214) * y -0.010557625006) * y  
          +0.011630447319) * y -0.009279453341) * y  
          +0.005353579108) * y -0.002141268741) * y  
          +0.000535310849) * y +0.999936657524*1;      
     }          
     }  
var outp=((zval > 0.0 ? ((x*1+1.0*1) * 0.5) : ((1.0 -x) * 0.5))) 
if ((outp>1)||(outp<-1)) (outp=1) 
}
return (outp) 
} 

function odd(number)
{
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;
   }
return (1-sum*mult*numerator/denominator);
}

 
//--------------- start code changes by Brent Meeker ------------------

function BinomialCoeff(a,b)//Ways of taking a things b at a time.
{if (b < 1) 
   {return 1 }
 else 
   {return (a / b)*BinomialCoeff (a-1,b-1)}}

function RunsEven(r1, r2, k) //number of ways runs=k when k is even
{
return 2*BinomialCoeff(r1-1,(k-2)/2)*BinomialCoeff(r2-1,(k-2)/2)
}

function RunsOdd(r1,r2,k) //~half number of ways runs=k when k is odd
{
return BinomialCoeff(r1-1,(k-1)/2)*BinomialCoeff(r2-1,(k-3)/2)
}

function RunsProb(r1,r2,k,d)//Prob of exactly k runs 
{
if (k%2>0) 
   {return (RunsOdd(r1,r2,k) + RunsOdd(r2,r1,k))/d }
else
return RunsEven(r1,r2,k)/d 
}

function RunsDown(r1,r2,k,kbar) //Sums the prob of runs from k down.
{
sum = 0;
 prob = 1;
 rmin = Math.min(r1,r2);
 d = BinomialCoeff(r1*1 + r2*1,rmin);//just calculate d once for efficiency 
 for (k;k>kbar || (k>1 && k*prob > 0.00001); k=k-1)
 //When k<kbar the remaining cumulative prob is less than k*prob(exactly k runs).
	{ prob = RunsProb(r1,r2,k,d);
	  sum = sum + prob;
	}
return sum 
}

function WW(N1,N2,Runs)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";
var expruns=((2*N1*N2)/(N1*1+N2*1))+1*1
var sdruns=Math.sqrt((2*N1*N2*(2*N1*N2-N1-N2))/((N1*1+N2*1)*(N1*1+N2*1)*(N1*1+N2*1-1)))

var zruns=(Runs-expruns)/sdruns
var pvalue=zpr(zruns);
document.form1.outp.value+="Expected Number of Runs: "+truncate(expruns,1)+"; sd: " +truncate(sdruns,4)+writeln
  +"z-value= " +cut(zruns,7)+"; approx. probability: "+truncate(pvalue,5)+writeln 

zruns=(Runs-expruns+0.5)/sdruns    //continuity correction
pvalue=zpr(zruns);
document.form1.outp.value+="z-val= " +cut(zruns,6)+"(continuity correct.); p: "+truncate(pvalue,5)+writeln 

if (Runs<101)
{
document.form1.outp.value +=" BinomialCoeff(a,b): " + BinomialCoeff(N1,N2)+writeln
document.form1.outp.value +=" RunsEven(N1,N2,Runs): " + RunsEven(N1,N2,Runs)+writeln
document.form1.outp.value +=" RunsOdd(N1,N2,Runs): " +  RunsOdd(N1,N2,Runs)+writeln
document.form1.outp.value +=" RunsProb(r1,r2,k,d): " + RunsProb(N1,N2,Runs,expruns)+writeln
document.form1.outp.value +=" RunsDown(r1,r2,k,kbar): " +  RunsDown(N1,N2,Runs,expruns)+writeln
pvalue=RunsDown(N1,N2,Runs,expruns) //Use exact formula
document.form1.outp.value +="exact probability of " +truncate(Runs,5)+" or fewer runs= "+truncate(pvalue,5)+writeln+writeln
}
else
document.form1.outp.value +=writeln

return
}
//--------- end code changes by Brent Meeker --------------------

function MannW(Num1,Num2,Tot1)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

NTot=Num1*1+Num2*1
var Totsum=(NTot*(NTot*1+1*1))/2
var Tot2=Totsum-Tot1
document.form1.outp.value +="Total Number of Cases= "+NTot+writeln+"Total rank sum= "+truncate(Totsum,1)+writeln+"Total observed for group 2= "+Tot2+writeln
if (Tot2<Tot1) document.form1.outp.value +="Providing the lower rank sum is the prefered mode of input"+writeln
var expt1=0.5*Num1*(Num1*1+Num2*1+1*1)
var expt2=0.5*Num2*(Num1*1+Num2*1+1*1)
var varexpt=Math.sqrt(Num1*Num2*(Num1*1+Num2*1+1*1)/12)
document.form1.outp.value +="Sum1= "+Tot1+"; Expected= "+truncate(expt1,1)+writeln
document.form1.outp.value +="Sum2= "+Tot2+"; Expected= "+truncate(expt2,1)+writeln
document.form1.outp.value +="Std Dev of Sums "+truncate(varexpt,2)+writeln
var z=(Tot1-Tot2-((Num1-Num2)*(Num1*1+Num2*1+1*1)*0.5))/Math.sqrt(Num1*Num2*(Num1*1+Num2*1+1*1)/3)
var pvalue=1
if ((z<5)&(z>-5)) pvalue=zpr(z)
document.form1.outp.value +="z-value of differenc= "+truncate(z,3)
      +writeln+"probability= " +(pvalue)+"(1-p= "+truncate(1-pvalue,6)+")"+writeln
return
}

function KS(N1,N2,D)
{
writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n";

if (D>1) document.form1.outp.value +="The number in the third box should be a"+writeln+"proportional difference, between zero and one"+writeln
else
{var ch2=4*D*D*N1*N2/(N1*1+N2*1)
document.form1.outp.value +="The Chi-square value of this largest difference"+writeln+"equals: "+truncate(ch2,3)+writeln
document.form1.outp.value +="The probability of this largest difference"+writeln+"equals: "+cut(c2prob(ch2,2),7)
}
return
}

function ClearOutp() 
{
var writeln="\n";
if (navigator.appVersion.lastIndexOf('Win') != -1) writeln="\r\n"; 
document.form1.outp.value ="cleared"+writeln;
}


