Mega Code Archive

 
Categories / JavaScript DHTML / Page Components
 

Reverse Polish Notation Calculator

<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 = &lt;-             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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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">&nbsp;</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">&nbsp;</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>&nbsp;</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>&nbsp;</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=" &lt;- " 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=&lt;-, 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: -->