

function compute(){
var outwin=document.theform.textout.value;

var c=0, n=0, cl=95;
c=parseInt(document.theform.obscolors.value);
n=parseInt(document.theform.samsize.value);
cl=parseFloat(document.theform.conf.value);


if (isNaN(n))
        {
        alert("The sample size is not a number.");
        return;
        }
if (n<=0)
        {
        alert("The sample size must be at least 1.");
        return;
        }
if (isNaN(c))
        {
        alert("The number of observed colors is not a number.");
        return;
        }
if ((c<0)||(c>n))
        {
        alert("The number of observed colors must be between zero "+
                "and the sample size, inclusive.");
        return;
        }
if (isNaN(cl))
        {
        alert("The confidence level is not a number.");
        return;
        }
if ((cl<=0)||(cl>=100))
        {
        alert("The confidence level must be between "+
                "zero and 100, exclusive.");
        return;
        }


var out="";
out +="Here "+c+" colors were observed in a "+
        "sample of size "+n+" with replacement.\n";
if (c==n)
{
out+="The MLE does not exist.\n";
}
else
{
out +="The MLE of the total number of colors is "+
        couponmle(n, c)+".\n";
}
out +="The lower endpoint of a one sided "+
        cl+"% confidence interval for the ";
out +="total number of colors is "+
        couponlower(n, c, (100-cl)/100)+".\n";
out +="The upper endpoint of a one sided "+
        cl+"% confidence interval for the ";
out +="total number of colors is "+
        couponupper(n, c, (100-cl)/100)+".\n";
out +="The endpoints of a two sided "+
        cl+"% confidence interval for the ";
out +="total number of colors are "+
        couponlower(n, c, (100-cl)/200)+" and ";
out +=""+couponupper(n, c, (100-cl)/200)+".\n\n";

document.theform.textout.value=out+outwin;
}



function color_distribution(n, k, c){
var j, old_density, new_density;
var density=new Array(2*c+2);
for(j=0;j<=2*c+1;j++) density[j]=0;
old_density=0;
new_density=c+1;
density[1]=1;

var  m;
for(m=2;m<=n;m++)
        {
        for(j=1;j<=c;j++)
                {
                density[new_density+j]=( j*density[old_density+j] +
                         (k-j+1)*density[old_density+j-1] )/k;
                }
        j=old_density;
        old_density=new_density;
        new_density=j;
        }


var dist;
dist=0;
for(j=1;j<=c;j++)
        {
        dist=dist+density[old_density+j];
        }

return dist;
}


function couponmle(n, c){
if(n==c) return(Number.POSITIVE_INFINITY);
var low, high, test;
low=c;
high=c;
while( (high+1)*Math.pow( (high)/(high+1),  n) >(high+1-c) )
        {
        low=high;
        high=2*high;
        }
while( high-low >1)
        {
        test=Math.floor((high+low)/2);
        if ((test+1)*Math.pow( (test)/(test+1),  n) >(test+1-c) )
                {
                low=test;
                }
        else
                {
                high=test;
                }
        }
return high;
}


function couponlower(n, c, alpha){
var low, high, test;
low=c-1;
high=2*c;
while( color_distribution(n, high ,c-1) >= 1-alpha )
        {
        low=high;
        high=2*high;
        }
while( high-low >1)
        {
        test=Math.floor((high+low)/2);
        if ( color_distribution(n, test, c-1) < 1-alpha )
                {
                high=test;
                }
        else
                {
                low=test;
                }
        }
return high;
}


function couponupper(n, c, alpha){
if(n==c) return (Number.POSITIVE_INFINITY);
var low, high, test;
low=c;
high=2*c;
while( color_distribution(n, high ,c) > alpha )
        {
        low=high;
        high=2*high;
        }
while( high-low >1)
        {
        test=Math.floor((high+low)/2);
        if ( color_distribution(n, test, c) <=alpha )
                {
                high=test;
                }
        else
                {
                low=test;
                }
        }
return low;
}


