<html> <head> <title>rpnjcalc a javascript RPN Calculator</title> <style type="text/css"> input.btn {align:center;color:#000000;width:50;height:22;vertical-align:middle;font-size:12} input.bigbtn {align:center;color:#000000;width:100;height:22;vertical-align:middle;font-size:12} </style>
<script type="text/javascript" language="JavaScript">
<!-- hide this script contents from old browsers
// keep track of whether we just computed display.value var computed = true; var dgmode = 1; // rad mode is default var enterpressed = false; var undostack=new Array(5); var lastxvalue=0;
// init: undostack[4]=0; undostack[3]=0; undostack[2]=0; undostack[1]=0; undostack[0]=0;
// f=form object function pushStack(f) { f.stack3.value = f.stack2.value; f.stack2.value = f.stack1.value; f.stack1.value = f.stack.value; f.stack.value = f.display.value; } // for the pop button: role down all. // f=form object function popStackDisplay(f) { f.display.value = f.stack.value; f.stack.value = f.stack1.value; f.stack1.value = f.stack2.value; f.stack2.value = f.stack3.value; computed = true; } // pop just the upper stack // f=form object function popStack(f) { f.stack.value = f.stack1.value; f.stack1.value = f.stack2.value; f.stack2.value = f.stack3.value; } // f=form object function fillundostack(f) { undostack[4]=f.stack3.value; undostack[3]=f.stack2.value; undostack[2]=f.stack1.value; undostack[1]=f.stack.value; undostack[0]=f.display.value; lastxvalue=f.display.value; }
// f=form object function undoall(f) { f.stack3.value= undostack[4]; f.stack2.value= undostack[3]; f.stack1.value= undostack[2]; f.stack.value = undostack[1]; f.display.value=undostack[0]; computed=true; }
// f=form object function lastx(f) { f.display.value=lastxvalue; computed=true; }
// make sure we have a number in the display function isnotafinatenumber(f) { var tmp; tmp=parseFloat(f.display.value); if(isNaN(tmp) || ! isFinite(tmp)){ return(true); } return(false); }
// the enter button // f=form object function enterx(f) { fillundostack(f); if(isnotafinatenumber(f)){ f.display.value="0"; }else{ pushStack(f); } enterpressed = true; computed = false; } // the C (clear) button // f=form object function cx(f) { fillundostack(f); f.display.value = 0 ; computed = false; }
// recall X // f=form object function rcl1(f) { fillundostack(f); // auto-push the stack if the last value was computed if(computed) { if(isnotafinatenumber(f)){ f.display.value="0"; } pushStack(f); } if(isNaN(f.mem1.value) || ! isFinite(f.mem1.value)){ f.mem1.value=0; } f.display.value=f.mem1.value; computed = true; }
// recall X // f=form object function rcl2(f) { fillundostack(f); // auto-push the stack if the last value was computed if(computed) { if(isnotafinatenumber(f)){ f.display.value="0"; } pushStack(f); } if(isNaN(f.mem2.value) || ! isFinite(f.mem2.value)){ f.mem2.value=0; } f.display.value=f.mem2.value; computed = true; }
// recall X // f=form object function rcl3(f) { fillundostack(f); // auto-push the stack if the last value was computed if(computed) { if(isnotafinatenumber(f)){ f.display.value="0"; } pushStack(f); } if(isNaN(f.mem3.value) || ! isFinite(f.mem3.value)){ f.mem3.value=0; } f.display.value=f.mem3.value; computed = true; }
// recall X // f=form object function rcl4(f) { fillundostack(f); // auto-push the stack if the last value was computed if(computed) { if(isnotafinatenumber(f)){ f.display.value="0"; } pushStack(f); } if(isNaN(f.mem4.value) || ! isFinite(f.mem4.value)){ f.mem4.value=0; } f.display.value=f.mem4.value; computed = true; }
// store X // f=form object function sto1(f) { f.mem1.value=f.display.value; }
// store X // f=form object function sto2(f) { f.mem2.value=f.display.value; }
// store X // f=form object function sto3(f) { f.mem3.value=f.display.value; }
// store X // f=form object function sto4(f) { f.mem4.value=f.display.value; }
// add a new character to the display // object passed is the form object and the character(s) function addChar(f, character) { var tmpvar; if (computed || enterpressed) { fillundostack(f); } // auto-push the stack if the last value was computed if(computed) { if(isnotafinatenumber(f)){ f.display.value="0"; } pushStack(f); f.display.value = ""; computed = false; } if(enterpressed) { f.display.value = ""; computed = false; enterpressed = false; } tmpvar=f.display.value;
// make sure f.display.value is a string if(tmpvar.match(/^[0-9.-eE]+$/)){ f.display.value += character; }else{ f.display.value = character; } }
// f=form object function deleteChar(f) { if (computed || enterpressed) { fillundostack(f); f.display.value = 0; computed = false; enterpressed = false; }else{ f.display.value = f.display.value.substring(0, f.display.value.length - 1); } }
function powxy(f) { var tmpvar; fillundostack(f); tmpvar = Math.pow(parseFloat(f.stack.value),parseFloat(f.display.value)); f.display.value = tmpvar; computed = true; popStack(f); }
function square(f) { fillundostack(f); f.display.value = parseFloat(f.display.value) * parseFloat(f.display.value); computed = true; }
function sqrtx(f) { fillundostack(f); f.display.value = Math.sqrt(parseFloat(f.display.value)); computed = true; }
function expx(f) { fillundostack(f); f.display.value = Math.exp(parseFloat(f.display.value)); computed = true; }
function lnx(f) { fillundostack(f); f.display.value = Math.log(parseFloat(f.display.value)); computed = true; }
// the 0.000...1 is to handle rounding errors better function log10(f) { fillundostack(f); f.display.value = Math.log(parseFloat(f.display.value))/(Math.LN10 - 0.00000000000000001); computed = true; }
// ln(gamma(x)) // x is the actual value not a form object function internal_loggamma(x) { with(Math) { var v=1; var w=0; var z=0; while ( x<8 ) { v*=x; x++ } w=1/(x*x); return ((((((((-3617/122400)*w + 7/1092)*w -691/360360)*w + 5/5940)*w -1/1680)*w + 1/1260)*w -1/360)*w + 1/12)/x + 0.5 * log(2*PI)-log(v)-x+(x-0.5)*log(x) ; } }
// gamma function // x is the actual value not a form object function internal_gamma(x) { with(Math) { if ( x <= 0 ) { if (abs(x)-floor(abs(x))==0 ) // should be complex infinity but we do not have // complex numbers return Number.POSITIVE_INFINITY; else return PI/( sin(PI*x) * exp( internal_loggamma(1-x) ) ); }else return exp(internal_loggamma(x)) ; } }
// calculate the factorial including non integer factorial // Integer factorial is: n!= n* (n-1)! // Non interger is: n!=gamma(n+1) function internal_factorial(n) { with(Math) { if (n<0) /* if negative */ return internal_gamma(n+1); else if ((n == 0) || (n == 1)) return 1; else if (abs(n)-floor(abs(n))==0 ) { // positive integer var buf = 1; var i; for (i=1;i<=n;i++) { buf = buf*i; } return buf; }else // if non-integer return internal_gamma(n+1); } }
// this function can be used directly from the gui function factx(f) { fillundostack(f); if(isnotafinatenumber(f)){ f.display.value =Number.NaN; }else{ f.display.value = internal_factorial(parseFloat(f.display.value)); computed = true; } } // toggle the mode between deg and rad function changedegrad(button) { if( dgmode == "1.0" ) { button.value = " deg"; dgmode = Math.PI/180.0; } else { button.value = " rad "; dgmode = 1.0; } }
function sin(f){ fillundostack(f); f.display.value = Math.sin(parseFloat(f.display.value)*dgmode); computed = true; }
function asin(f){ fillundostack(f); f.display.value = Math.asin(parseFloat(f.display.value))/dgmode; computed = true; }
function cos(f){ fillundostack(f); f.display.value = Math.cos(parseFloat(f.display.value)*dgmode); computed = true; }
function acos(f){ fillundostack(f); f.display.value = Math.acos(parseFloat(f.display.value))/dgmode; computed = true; }
function tan(f){ fillundostack(f); f.display.value = Math.tan(parseFloat(f.display.value)*dgmode); computed = true; }
function atan(f){ fillundostack(f); f.display.value = Math.atan(parseFloat(f.display.value))/dgmode; computed = true; }
// put pi (3.1415... into x) function pix(f){ fillundostack(f); if(computed) { if(isnotafinatenumber(f)){ f.display.value = Math.PI; }else{ pushStack(f); f.display.value = Math.PI; } }else{ f.display.value = Math.PI; } computed = true; }
function onebyx(f) { var tmpvar; fillundostack(f); tmpvar = parseFloat(f.display.value); if (isNaN(tmpvar) || tmpvar == 0){ f.display.value =Number.NaN; computed = false; }else{ f.display.value = 1 / tmpvar; computed = true; } }
function swapxy(f) { var tmpvar; fillundostack(f); tmpvar = f.display.value; if(isNaN(tmpvar) || tmpvar == "" ){ tmpvar="0"; } f.display.value = f.stack.value; f.stack.value = tmpvar; computed = true; }
function add(f) { fillundostack(f); f.display.value = parseFloat(f.stack.value) + parseFloat(f.display.value); computed = true; popStack(f); }
function subtract(f) { fillundostack(f); f.display.value = f.stack.value - f.display.value; computed = true; popStack(f); }
function multiply(f) { fillundostack(f); f.display.value = f.stack.value * f.display.value; computed = true; popStack(f); }
function divide(f) { fillundostack(f); var divisor = parseFloat(f.display.value); if(divisor == 0) { f.display.value = Number.POSITIVE_INFINITY; }else{ f.display.value = f.stack.value / divisor; } computed = true; popStack(f); }
// object passed is form function changeSign(f) { fillundostack(f); // we could use f.display.value = 0 - f.display.value but // we might get rounding errors if(f.display.value.substring(0, 1) == "-") f.display.value = f.display.value.substring(1, f.display.value.length); else f.display.value = "-" + f.display.value; }
// keyboard interface
// handle the differences between MSIE and Netscape function getkey(e) { if (window.event) return window.event.keyCode; else if (e) return e.which; else return null; }
// http://www.faqs.org/docs/htmltut/forms/_INPUT_onKeyPress.html function chkkey(e) { var key, keychar; key = getkey(e); if (key == null) return true; if (key == 13){ // enter pressed enterx(document.rpncal); }else if (key == 8){ // backspace deleteChar(document.rpncal); }else{ // get character keychar = String.fromCharCode(key); if ((("0123456789.").indexOf(keychar) > -1)){ addChar(document.rpncal,keychar); }else if (keychar == "e" ){ expx(document.rpncal); }else if (keychar == "l" ){ lnx(document.rpncal); }else if (keychar == "^" ){ powxy(document.rpncal); }else if (keychar == "r" ){ onebyx(document.rpncal); }else if (keychar == "d" ){ // d or backspace = <- deleteChar(document.rpncal); }else if (keychar == "C" ){ cx(document.rpncal); }else if (keychar == "c" ){ changeSign(document.rpncal); }else if (keychar == "s" ){ // s = swap swapxy(document.rpncal); }else if (keychar == "p" ){ // p = pop popStackDisplay(document.rpncal); }else if (keychar == "-" ){ subtract(document.rpncal); }else if (keychar == "+" ){ add(document.rpncal); }else if (keychar == "*" ){ multiply(document.rpncal); }else if (keychar == "/" ){ divide(document.rpncal); } // c = +/- } }
function printkey(e) { var key, keychar; key = getkey(e); if (key == null) return true; // get character keychar = String.fromCharCode(key); keychar = keychar.toLowerCase(); alert("key is: "+ key + "c: "+keychar); }
//<!-- done hiding from old browsers -->
</script> </head>
<body> <h1><font color="darkblue">Reverse Polish Notation Calculator</font></h1>
<p>This calculator uses postfix notation also known as Reverse Polish Notation (RPN). This notation has many advantages over Algebraic notation. One advantage is that you can calculate even complicated terms without braces.</p>
<p>An example: Suppose you want calculate 5 * (3 + 4)<br> Press the following keys on the calculator: 5, enter, 3, enter. The 3 and 5 did go into the calculator's memory, the stack. Now you type 4 and press + to add. After this you just press * to multiply.</p>
<p>You can either operate this calculator with mouse clicks or <b><font color="#008800">you can use the keyboard</font></b>. However some web-browsers have keyboard shortcuts which may conflict with the keys used by this calculator. Therefore you need to place the mouse over the text area below as this avoids the browsers keyboard shortcuts to take effect. The keyboard interface was tested with Mozilla, MS IE and Opera. It does not work with Netscape 4.</p>
<p>rpnjcalc comes with a small manual which you can find here: <a href="rpnjcalc-help-0.1.html">rpnjcalc-help-0.1.html</a></p> <hr>
<center> <form name="rpncal" method="post"> <table border="4" cellpadding="0" cellspacing="1" bgcolor= "#CCCCCC" summary="calculator"> <tr> <td colspan="7" align="center"><font color="#0000AA"> rpnjcalc version 1.6</font></td> </tr>
<tr> <td colspan="4"><input type="button" value="stoX" onclick="sto4(this.form)"> <input name="mem4" value="0" size="14"> <input type="button" value="rclX" onclick= "rcl4(this.form)"> </td>
<td colspan="3" bgcolor="#AAAABB">C:<input name= "stack3" value="0" size="23" readonly> </td> </tr>
<tr> <td colspan="4"><input type="button" value="stoX" onclick="sto3(this.form)"> <input name="mem3" value="0" size="14"> <input type="button" value="rclX" onclick= "rcl3(this.form)"> </td>
<td colspan="3" bgcolor="#AAAABB">B:<input name= "stack2" value="0" size="23" readonly> </td> </tr>
<tr> <td colspan="4"><input type="button" value="stoX" onclick="sto2(this.form)"> <input name="mem2" value="0" size="14"> <input type="button" value="rclX" onclick= "rcl2(this.form)"> </td>
<td colspan="3" bgcolor="#AAAABB">A:<input name= "stack1" value="0" size="23" readonly> </td> </tr>
<tr> <td colspan="4"><input type="button" value="stoX" onclick="sto1(this.form)"> <input name="mem1" value="0" size="14"> <input type="button" value="rclX" onclick= "rcl1(this.form)"> </td>
<td colspan="3" bgcolor="#AAAABB">Y:<input name="stack" value="0" size="23" readonly> </td> </tr>
<tr> <td><input type="button" class="btn" value="undo" onclick= "undoall(this.form)"> </td> <td><input type="button" class="btn" value="lastX" onclick= "lastx(this.form)"> </td> <td><input type="button" class="btn" value="swap" onclick= "swapxy(this.form)"> </td> <td colspan="1"> </td> <!-- the display line should be writable so you can do copy and paste -->
<td colspan="3" bgcolor="#AAAABB">X:<input name= "display" value="0" size="23"> </td> </tr>
<tr> <td><input type="button" class="btn" value=" sin " onclick= "sin(this.form)"> </td>
<td><input type="button" class="btn" value="asin " onclick= "asin(this.form)"> </td>
<td><input type="button" class="btn" value=" PI " onclick= "pix(this.form)"> </td>
<td><input type="button" class="btn" value=" 1/x " onclick= "onebyx(this.form)"> </td>
<td><input type="button" class="btn" value=" y^x " onclick= "powxy(this.form)"> </td>
<td><input type="button" class="btn" value=" log " onclick= "log10(this.form)"> </td>
<td><input type="button" class="btn" value=" E " onclick= "addChar(this.form, 'E')"> </td> </tr>
<tr> <td><input type="button" class="btn" value=" cos " onclick= "cos(this.form)"> </td>
<td><input type="button" class="btn" value="acos" onclick= "acos(this.form)"> </td>
<td><input type="button" class="btn" value=" 7 " onclick= "addChar(this.form, '7')"> </td>
<td><input type="button" class="btn" value=" 8 " onclick= "addChar(this.form, '8')"> </td>
<td><input type="button" class="btn" value=" 9 " onclick= "addChar(this.form, '9')"> </td>
<td><input type="button" class="btn" value=" / " onclick= "divide(this.form)"> </td>
<td><input type="button" class="btn" value=" E- " onclick= "addChar(this.form, 'E-')"> </td> </tr>
<tr> <td><input type="button" class="btn" value=" tan " onclick= "tan(this.form)"> </td>
<td><input type="button" class="btn" value="atan " onclick= "atan(this.form)"> </td>
<td><input type="button" class="btn" value=" 4 " onclick= "addChar(this.form, '4')"> </td>
<td><input type="button" class="btn" value=" 5 " onclick= "addChar(this.form, '5')"> </td>
<td><input type="button" class="btn" value=" 6 " onclick= "addChar(this.form, '6')"> </td>
<td><input type="button" class="btn" value=" * " onclick= "multiply(this.form)"> </td>
<td><input type="button" class="btn" value=" x! " onclick= "factx(this.form)"> </td> </tr>
<tr> <td><input type="button" class="btn" value=" ^2 " onclick= "square(this.form)"> </td>
<td><input type="button" class="btn" value=" sqrt " onclick= "sqrtx(this.form)"> </td>
<td><input type="button" class="btn" value=" 1 " onclick= "addChar(this.form, '1')"> </td>
<td><input type="button" class="btn" value=" 2 " onclick= "addChar(this.form, '2')"> </td>
<td><input type="button" class="btn" value=" 3 " onclick= "addChar(this.form, '3')"> </td>
<td><input type="button" class="btn" value=" - " onclick= "subtract(this.form)"> </td>
<td> </td> </tr>
<tr> <td><input type="button" class="btn" value=" e^x " onclick= "expx(this.form)"> </td>
<td><input type="button" class="btn" value=" ln " onclick= "lnx(this.form)"> </td>
<td><input type="button" class="btn" value=" 0 " onclick= "addChar(this.form, '0')"> </td>
<td><input type="button" class="btn" value=" . " onclick= "addChar(this.form, '.')"> </td>
<td><input type="button" class="btn" value=" +/- " onclick= "changeSign(this.form)"> </td>
<td><input type="button" class="btn" value=" + " onclick= "add(this.form)"> </td>
<td> </td> </tr>
<tr> <td>mode:</td>
<td><input type="button" class="btn" name="mode" value=" rad " onclick="changedegrad(this)"> </td>
<td><input type="button" class="btn" value=" C " onclick= "cx(this.form)"> </td>
<td><input type="button" class="btn" value=" <- " onclick= "deleteChar(this.form)"> </td>
<td><input type="button" class="btn" value=" pop " onclick= "popStackDisplay(this.form)"> </td>
<td colspan="2"><input type="button" class="bigbtn" value=" Enter " name=" enter " onclick="enterx(this.form)"> </td> </tr> </table> </form> <br> <form name="kbdfrom" onkeypress="javascript:chkkey(event)"> <small><textarea cols="76" rows="4" name="dummy" readonly onclick="this.style.backgroundColor='#BDBDBD'" onmouseout= "this.style.backgroundColor='#FFFFFF'"> For keyboard usage leave mouse cursor on this field and click once. Keys: 0-9.=numbers, return=enter, c=+/-, C=clear, s=swap, d=<-, p=pop, ^=y^x, l=ln, e=e^x, r=1/x </textarea></small> </form> </center> <br> <hr> <br> <!-- version is also written up in the table --> rpnjcalc was written by Guido Socher, guido at linuxfocus dot org, Copyright: GPL <!-- history: 1997-04-03 first version 2000-06-08 v0.8 several updateds 2003-10-12 v0.9 html faults removed. Tested on opera, mozilla, IE 2003-10-13 v1.0 more functions added 2003-10-16 v1.1 code cleanup Keyboard interface added. 2003-10-16 v1.2 more math functions added (trigonometry) 2003-10-17 v1.3 factorial added 2003-10-20 v1.4 undo/lastx/sto and rcl registers 2003-10-21 v1.5 fine tuning. Added help text. 2003-12-18 v1.6 autopush stack when pressing rcl
nice links: http://www.hpmuseum.org/ http://www.hp.com/calculators/ --> </body> </html> <!-- vim: set sw=4 ts=4 et: -->
|