<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: -->
|