//** G/G/s/c/p JavaScript Code (commented version): Random distributions **
// (c) Jaroslav Sklenar
//====================== Theoretical Distributions =======================
function uniform(min,max) {
var r = Math.random();
return min + r * (max - min)
};
//.........................................................................
function exponential(mean) {
var r = Math.random();
return - mean * Math.log(r);
};
//.........................................................................
function normal(mean, std) {
var x = 0;
for (var i = 1; i <= 12; i++) {
x += Math.random();
};
return (x - 6)*std + mean;
};
//====================== User Defined Distribution =======================
function distribution(name) { // Constructor
this.dname = name; // Properties
this.xv = new Array(); // Values
this.px = new Array(); // Probabilities
this.fx = new Array(); // Cumulative Distribution
this.size = -1;
this.status = "Table Empty";
this.confirmed = false;
this.disttype = "User"; // Types: User,Exp,Uni,Norm
this.enterMode = "Prob"; // Default modes
this.generMode = "Cont" // Others: Cumul, Discr
this.prompt1 = "Not used"; // Others: Mean,Min
this.par1 = 0;
this.prompt2 = "Not used"; // Others: Std,Max
this.par2 = 0;
};
//............................... methods .................................
function update(index) { with (this) {
switch (index) {
case 0 :
disttype = "User";
prompt1 = "Not used";
par1 = 0;
prompt2 = "Not used";
par2 = 0;
break;
case 1 :
disttype = "Exp";
prompt1 = "Mean";
par1 = 1;
prompt2 = "Not used";
par2 = 0;
break;
case 2 :
disttype = "Uni";
prompt1 = "Min";
par1 = 0;
prompt2 = "Max";
par2 = 1;
break;
case 3 :
disttype = "Norm";
prompt1 = "Mean";
par1 = 3;
prompt2 = "Std Dev";
par2 = 1;
break;
default :
alert("Index out of range - update.");
}
return true;
}};
distribution.prototype.update = update;
//.........................................................................
function testpar1(tx) { with (this) {
var x = parseFloat(tx);
if (! syntaxOK(x)) { return false };
switch (disttype) {
case "User" :
alert("Parameter not used.");
return false;
case "Exp" :
if (x <= 0) {
alert("The mean value must be positive.");
return false;
};
break;
case "Uni" :
if (x < 0 || x >= par2) {
alert("The minimum value must be non-negative and smaller than the maximum.");
return false;
};
break;
case "Norm" :
if (x <= 0) {
alert("The mean value must be positive.");
return false;
};
break;
default :
alert("Index out of range - update.");
};
par1 = x;
return true;
}};
distribution.prototype.testpar1 = testpar1;
//.........................................................................
function testpar2(tx) { with (this) {
var x = parseFloat(tx);
if (! syntaxOK(x)) { return false };
switch (disttype) {
case "User" :
alert("Parameter not used.");
return false;
case "Exp" :
alert("Parameter not used.");
return false;
case "Uni" :
if (x < 0 || x <= par1) {
alert("The maximum value must be greater than the minimum.");
return false;
};
break;
case "Norm" :
if (x <= 0) {
alert("The Standard Deviation must be positive.");
return false;
};
break;
default :
alert("Index out of range - update.");
};
par2 = x;
return true;
}};
distribution.prototype.testpar2 = testpar2;
//.........................................................................
function fixtable() { with (this) {
if (enterMode=="Prob") { // Entering probabilities
fx[0] = px[0];
for (var i = 1; i <= size; i++) {
fx[i] = fx[i-1] + px[i] }
} else { // Entering distr. function
px[0] = fx[0];
for (var i = 1; i <= size; i++) {
px[i] = fx[i] - fx[i-1] }
};
return true;
}};
distribution.prototype.fixtable = fixtable;
//.........................................................................
function last() { with (this) {
if (size < 0) {
return 0
} else {
return xv[size];
}
}};
distribution.prototype.last = last;
//.........................................................................
function compareWithLastValue(textElement) { with (this) {
var x = parseFloat(textElement);
if (! syntaxOK(x)) { return false };
if (size >= 0) {
if (x < xv[size]) {
alert("The value ( " + x + " ) must not be smaller than the previous one ( "
+ xv[size] + " ).");
return false;
}
};
return true;
}};
distribution.prototype.compareWithLastValue = compareWithLastValue;
//.........................................................................
function showTable() { with (this) {
var y = " # x p(x) F(x)" + "\n"
+ " ===================================" + "\n";
var s = "";
for (var i = 0; i <= size; i++) {
var l = " " + i;
l += spaces(4-l.length) + xv[i];
s = "" + px[i];
l += spaces(14-l.length) + s.slice(0,12);
s = "" + fx[i];
l += spaces(28-l.length) + s.slice(0,12) + "\n";
y += l;
};
if (size==-1) {
status = "Table Empty";
} else {
if (confirmed) {
status = "Table OK";
} else {
status = "Editing Table";
}
};
return y;
}};
distribution.prototype.showTable = showTable;
//.........................................................................
function accept(tx,tp) { with (this) {
if (enterMode == "Prob") { // Entering probabilities
confirmed = false;
size++;
xv[size] = parseFloat(tx);
px[size] = parseFloat(tp);
if (size==0) {
fx[size] = px[size];
} else {
fx[size] = fx[size-1] + px[size];
}
} else { // Entering distr. function
var fxx = parseFloat(tp);
if (fxx < fx[size]) {
alert("The F(x) value ( " + fxx + " ) must not be smaller than the previous one ( "
+ fx[size] + " ).");
return false;
} else {
confirmed = false;
size++;
xv[size] = parseFloat(tx);
fx[size] = fxx;
if (size==0) {
px[size] = fx[size];
} else {
px[size] = fx[size] - fx[size-1];
}
}
};
return true;
}};
distribution.prototype.accept = accept;
//.........................................................................
function edit() { with (this) {
var n = parseInt(prompt("Enter the number of the entry to be edited:"));
if ((isNaN(n))||(n<0)||(n>size)) {
alert("Not a correct entry number or empty table.");
return false;
};
var x = parseFloat(prompt("Enter the new value (x) of the entry " + n + " :",xv[n]));
if (! syntaxOK(x)) { return false };
if (enterMode=="Prob") { // Entering probabilities
var p = parseFloat(prompt("Enter the new probability (p) of the entry "
+ n + " :",px[n]));
} else { // Entering distr. function
var p = parseFloat(prompt("Enter the new cumulative probability (F) of the entry "
+ n + " :",fx[n]))
};
if (isNaN(p)) {
alert("Syntax error - the probability is not a number.");
return false;
};
if ((p < 0) || (p > 1)) {
alert("The probability must be a non-negative number not greater than 1.");
return false
}; // All seems OK
confirmed = false;
xv[n] = x;
if (enterMode=="Prob") { // Entering probabilities
px[n] = p;
} else {
fx[n] = p;
};
fixtable();
return true;
}};
distribution.prototype.edit = edit;
//.........................................................................
function insert() { with (this) {
var n = parseInt(prompt("Enter the number of the entry to be inserted (the current entry with this number and all succeeding will be moved):"));
if ((isNaN(n))||(n<0)||(n>size)) {
alert("Not a correct entry number or empty table.");
return false;
};
var x = parseFloat(prompt("Enter the value (x) of the entry " + n + " :",xv[n]));
if (! syntaxOK(x)) { return false };
if (enterMode=="Prob") { // Entering probabilities
var p = parseFloat(prompt("Enter the probability (p) of the entry "
+ n + " :",px[n]));
} else { // Entering distr. function
var p = parseFloat(prompt("Enter the cumulative probability (F) of the entry "
+ n + " :",fx[n]))
};
if (isNaN(p)) {
alert("Syntax error - the probability is not a number.");
return false;
};
if ((p < 0) || (p > 1)) {
alert("The probability must be a non-negative number not greater than 1.");
return false;
}; // All seems OK
confirmed = false;
size++;
for (var i = size; i > n; i--) { // Shift all up
xv[i] = xv[i-1];
px[i] = px[i-1];
fx[i] = fx[i-1];
};
xv[n] = x;
if (enterMode=="Prob") { // Entering probabilities
px[n] = p;
} else {
fx[n] = p;
};
fixtable();
return true;
}};
distribution.prototype.insert = insert;
//.........................................................................
function deleteit() { with (this) {
var n = parseInt(prompt("Enter the number of the entry to be deleted:"));
if ((isNaN(n))||(n<0)||(n>size)) {
alert("Not a correct entry number or empty table.");
return false
};
confirmed = false;
if (size==0) { // one item only
size = -1;
xv.length = 0; // truncating the arrays
px.length = 0;
fx.length = 0;
} else {
for (var i = n; i <= size-1; i++) { // Move the rest down
xv[i] = xv[i+1];
px[i] = px[i+1];
fx[i] = fx[i+1];
};
size--;
fixtable()
};
return true;
}};
distribution.prototype.deleteit = deleteit;
//.........................................................................
function cleartable() { with (this) {
size = -1;
xv.length = 0;
px.length = 0;
fx.length = 0;
confirmed = false;
return true;
}};
distribution.prototype.cleartable = cleartable;
//.........................................................................
function confirmtable() { with (this) {
confirmed = false;
if (size == -1) {
alert("The table is empty !");
return false;
};
for (var i = 1; i <= size; i++) {
if (xv[i] < xv[i-1]) {
alert("The values (x) in the table are not in non-decreasing order. This has to be corrected.");
return false;
}
};
if (enterMode=="Prob") { // Entering probabilities
fx[0] = px[0];
var sofarOK = true;
for (var i = 1; i <= size; i++) {
fx[i] = fx[i-1] + px[i];
if (fx[i]>1) {
fx[i] = 1;
sofarOK = false;
}
};
if (! sofarOK) {
if (! confirm("Sum of probabilities is greater than 1. That's why some F(x) are truncated to 1. Is this OK ?")) {
return false;
}
}
} else { // Entering distr. function
px[0] = fx[0];
for (var i = 1; i <= size; i++) {
if (fx[i] < fx[i-1]) {
alert("The values of the cumulative distribution are not in non-decreasing order. This has to be corrected.");
return false;
};
px[i] = fx[i] - fx[i-1];
}
};
if ((px[0]>0) && (generMode=="Cont")) {
if (! confirm("The first probability value of a continuous random variable is greater than 0. Note that the generator will assume the implicit starting point (0,0). Is this correct ?")) {
return false;
}
};
if (fx[size]<1) {
if (confirm("Sum of probabilities is less than 1, but the last value of F(x) must be equal to 1. Do you want to set it to value 1 ?")) {
fx[size] = 1;
} else return false;
};
confirmed = true;
return true;
}};
distribution.prototype.confirmtable = confirmtable;
//.........................................................................
function generate() { with (this) { // Generates random number
switch (disttype) {
case "User" :
var x1 = 0, f1 = 0, i = 0; // xv = array with values
var x2 = xv[0], f2 = fx[0]; // fx = cumulative distribution
var r = Math.random();
while (r > f2) { // search for c.d.f. not smaller than r
x1 = x2; f1 = f2;
x2 = xv[++i], f2 = fx[i];
};
if (generMode=="Discr") {
return x2; // return the value for a discrete variable
} else {
return x1 + (x2-x1)*(r-f1)/(f2-f1); // Interpolation for a continuous variable
}
case "Exp" :
return exponential(par1);
case "Uni" :
return uniform(par1,par2);
case "Norm" : // Must be non-negative
var x = normal(par1,par2);
while (x<0) {
x = normal(par1,par2);
};
return x;
default :
alert("Index out of range - update.");
return false;
};
}};
distribution.prototype.generate = generate;
//=========================================================================