Reverse Polish Notation Calculator : Calculator : Page Components JAVASCRIPT DHTML TUTORIALS


JAVASCRIPT DHTML TUTORIALS » Page Components » Calculator »

 

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 = ;
    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<) { 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 <= ) {
            if (abs(x)-floor(abs(x))==)
                // should be complex infinity but we do not have
                // complex numbers
                return Number.POSITIVE_INFINITY; 
            else 
                return PI/sin(PI*x* expinternal_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))==) { // 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)
{
    ifdgmode == "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 = / 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(01== "-")
        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 == nullreturn 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 == nullreturn 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 (4)<br>
     Press the following keys on the calculator: 5, enter, 3,
    enter. The and did go into the calculator's memory, the
    stack. Now you type 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=ts=et: -->

           
       



-

Leave a Comment / Note


 
Verification is used to prevent unwanted posts (spam). .

Follow Navioo On Twitter

JAVASCRIPT DHTML TUTORIALS

 Navioo Page Components
» Calculator