randomfox (randomfox) wrote,
randomfox
randomfox

George Score Calculator in Javascript


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta http-equiv="Content-Language" content="en-us" />
<meta http-equiv="imagetoolbar" content="false" />
<meta name="MSSmartTagsPreventParsing" content="true" />
<meta name="author" content="Po Shan Cheah" />

<title>George Score calculator</title>

<script type="text/javascript">

function clearOutput() {
    var output = document.getElementById("output");
    while (output.firstChild)
	output.removeChild(output.firstChild);
}

// Write a string to the output area.
function write(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    output.appendChild(txt);
}

// Write a string with a newline to the output area.
function writeln(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var newline = document.createElement("br");
    output.appendChild(txt);
    output.appendChild(newline);
}

// Write a string in red to signify an error.
function errorln(str) {
    var output = document.getElementById("output");
    var txt = document.createTextNode(str);
    var newline = document.createElement("br");
    var span = document.createElement("span");
    // setAttribute("class" ...) does not work in IE.
    span.className = "error";
    span.appendChild(txt);
    span.appendChild(newline);
    output.appendChild(span);
}

// Format floating point number in fixed-point notation.
function fixedfmt(num, decimals) {
    // Number.toFixed is a Javascript 1.5 feature, so we need to test for it here.
    return num.toFixed ? num.toFixed(decimals) : num;
}

// Get numbers from the input fields.
function getInput() {
    var field = document.getElementById("billsentered");
    var obj = new Object();
    obj.be = parseInt(field.value);
    if (isNaN(obj.be) || obj.be < 0) {
	errorln("Invalid number '" + field.value + "' specified for bills entered. Need a non-negative number for this field.");
	return false;
    }
    field = document.getElementById("totalhits");
    obj.th = parseInt(field.value);
    if (isNaN(obj.th) || obj.th < 0) {
	errorln("Invalid number '" + field.value + "' specified for total hits. Need a non-negative number for this field.");
	return false;
    }
    field = document.getElementById("daysinactive");
    obj.di = parseInt(field.value);
    if (isNaN(obj.di) || obj.di < 0) {
	errorln("Invalid number '" + field.value + "' specified for days inactive. Need a non-negative number for this field.");
	return false;
    }

    return obj;
}

// Calculate George Score
function gs(be, th, di) {
    return 100 * (Math.sqrt(Math.log(be)) + Math.log(th + 1)) * (1 - di / 90);
}

function showneeded(hitpred, billpred) {
    writeln("Hits needed for 1GS  = " + fixedfmt(hitpred, 2));
    writeln("Bills needed for 1GS = " + fixedfmt(billpred, 2));
    writeln("Bill/Hit ratio       = " + fixedfmt(billpred / hitpred, 3));
    writeln(" ");
}

var epsilon = 1e-10;

function equal(a, b) {
    return Math.abs(a - b) < epsilon * Math.abs(a);
}

function iszero(a) {
    return Math.abs(a) < epsilon;
}

// Find an argument for which fn exceeds fn(0) by 1 or greater.
function getupper(fn) {
    var curgs = fn(0);
    var upper = 1;
    while (upper < 1e9) {
	if (fn(upper) - curgs >= 1)
	    return upper;
	upper *= 2;
    }
    return upper;
}

// Solve for x in the equation fn(x) - fn(0) = 1
// Uses linear interpolation.
function solve1gs(fn) {
    var curgs = fn(0);
    var a = 0;
    var b = getupper(fn);
    var itercount = 0;
    var xold = a;

    var fa = fn(a) - curgs - 1;
    var fb = fn(b) - curgs - 1;

    for (;;) {
	var newx = a - fa * (b - a) / (fb - fa);
	var newfx = fn(newx) - curgs - 1;

	itercount++;
	writeln(itercount + ": " + newx + " " + newfx);

	// Sanity check. If too many iterations, quit.
	if (itercount >= 500) {
	    writeln("Too many iterations. Ending.");
	    writeln(" ");
	    return newx;
	}

	// Sanity check. If we are getting invalid numbers, quit.
	if (isNaN(newx)) {
	    writeln("Solver failed. Ending.");
	    writeln(" ");
	    return newx;
	}

	// Check if close enough to a solution.
	if (equal(newx, xold) || iszero(newfx)) {
	    writeln(" ");
	    return newx;
	}
	xold = newx;

	if (fa * newfx > 0) {
	    a = newx;
	    fa = newfx;
	}
	else {
	    b = newx;
	    fb = newfx;
	}
    }
}

function main() {
    clearOutput();

    var input = getInput();
    if (!input)
	return false;

    writeln("Bills entered        = " + input.be);
    writeln("Total hits           = " + input.th);
    writeln("Days inactive        = " + input.di);
    writeln("George Score         = " + fixedfmt(gs(input.be, input.th, input.di), 3));
    writeln(" ");

    showneeded(
	(input.th + 1) / 100, 
	input.be * Math.sqrt(Math.log(input.be)) / 50);

    showneeded(
	solve1gs(function (incrhits) { return gs(input.be, input.th + incrhits, input.di); }),
	solve1gs(function (incrbills) { return gs(input.be + incrbills, input.th, input.di); }));
}
</script>

<style type="text/css">
body {
    background: #fff none;
    color: #000;
    font: normal 14px Tahoma, Verdana, Arial, Helvetica, sans-serif;
}

.error {
    color: red;
}

#output {
    white-space: pre;
    font: normal 14px monospace;
}
</style>
</head>

<body>
    <h1>George Score calculator</h1>
    <noscript>
	<span class="error">
	    The George Score calculator requires a browser that supports Javascript.<br />
	    Your browser either does not support Javascript or it has Javascript disabled. If you wish to run the solver, please upgrade your browser or enable Javascript support.<br />&nbsp;<br />
	</span>
    </noscript>

    <script type="text/javascript">
<!--
// Test for W3C DOM API.
if (document.getElementById) {
}
else {
    document.write('<span class="error">The George Score calculator requires a browser that supports the W3C DOM API.<br \/>Your browser does not support this API. If you wish to run the solver, please upgrade your browser. The latest versions of Mozilla Firefox, Opera, and Internet Explorer have support for this API.<br \/>&nbsp;<br \/><\/span>');
}
// -->
    </script>

    <form action="#" onsubmit="main(); return false;">
	<table cellpadding="5">
	    <tr>
		<td><label for="billsentered">Bills Entered:</label></td>
		<td><input type="text" name="billsentered" id="billsentered" size="20" value="100000" /></td>
	    </tr>
	    <tr>
		<td><label for="totalhits">Total Hits:</label></td>
		<td><input type="text" name="totalhits" id="totalhits" size="20" value="20000" /></td>
	    </tr>
	    <tr>
		<td><label for="daysinactive">Days Inactive:</label></td>
		<td><input type="text" name="daysinactive" id="daysinactive" size="20" value="0" /></td>
	    </tr>
	    <tr>
		<td colspan="2"><input type="submit" value="Calculate!" /></td>
	    </tr>
	</table>
    </form>

    <hr />
    <div id="output">
    </div>
</body>
</html>
<!--
Last updated: March 28, 2006
-->
<!-- vim:set tw=0: -->

Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 0 comments