Reverse Polish Notation Calculator : Calculator « Page Components « JavaScript DHTML

JavaScript DHTML
1. Ajax Layer
2. Data Type
3. Date Time
4. Development
5. Document
6. Event
7. Event onMethod
8. Form Control
9. GUI Components
10. HTML
11. Javascript Collections
12. Javascript Objects
13. Language Basics
14. Node Operation
15. Object Oriented
16. Page Components
17. Security
18. Style Layout
19. Table
20. Utilities
21. Window Browser
Microsoft Office Word 2007 Tutorial
Java
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
C# / C Sharp
C# / CSharp Tutorial
ASP.Net
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
PHP
Python
SQL Server / T-SQL
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
JavaScript DHTML » 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