reptile7's JavaScript blog
Thursday, June 23, 2016
 
Dr. Calculator and His eval( ) Powers
Blog Entry #370

Let's get back now to our ongoing analysis of the Another Great Science Calculator (AGSC) script. Near the end of the previous post, we saw that the AGSC script calls on a

function calculate(arg) { arg.expr.value = eval(arg.expr.value); }

to evaluate basic arithmetic expressions; we'll see below that we can leverage this functionality for a variety of other calculations, starting with...

Arithmetic extras

Factorials

The factorial operation is an application of multiplication. Many calculators have an key although Jamie's calculator isn't one of them. However, we know via this code in Blog Entry #75 that we can calculate a fact factorial with

fact = 1; for (i = x; i > 0; i--) fact *= i;

and if we plug the above expression with a suitable x operand into the expr field and click the key, then we do in fact get the x! value, e.g., fact = 1; for (i = 7; i > 0; i--) fact *= i; outputs 5040 (7!): this is a consequence of the fact that in JavaScript a fact = some_value expression itself evaluates to some_value.

It would be great if JavaScript had a Math.fact(x) method for computing factorials, but it doesn't.

Modulo

The modulo operation is an application of division. Most calculators, including Jamie's calculator, don't have a key (they do typically have a key for converting a number to a corresponding percent, i.e., dividing it by 100); nonetheless, we can calculate( ) a modulo remainder with Jamie's calculator upon inputting a dividend % divisor expression into the expr field, e.g., 200 % 16 outputs 8.

Exponentiation

Jamie's calculator offers a key for squaring a number and a key for taking the square root of a number.

function calc_sqrt(form) { form.expr.value = Math.sqrt(form.expr.value); }

function calc_sqr(form) { form.expr.value = (form.expr.value * 1) * (form.expr.value * 1); }

<td><input type="button" value=" Sqrt " onclick="calc_sqrt(this.form);"></td>
<td><input type="button" value="  Sqr  " onclick="calc_sqr(this.form);"></td>


• The * 1 multiplications in the calc_sqr( ) function are unnecessary as the attempted multiplication of two numeric strings gives the expected product.

The calculator doesn't have and keys for calculating other powers and roots, but there's nothing stopping us from inputting Math.pow(base, exponent) commands into the expr field and eval( )-ing them, is there? Math.pow(2, 10) outputs 1024, Math.pow(1024, 1/10) outputs 2.

Logarithms

The calculator offers a key for calculating common (base 10) logarithms and a key for calculating binary (base 2) logarithms.

var base_10 = Math.LN10;
var base_2 = Math.LN10;

function base10_log(form) { form.expr.value = Math.log(form.expr.value) / base_10; }

function base2_log(form) { form.expr.value = Math.log(form.expr.value) / base_2; }

<td><input type="button" value="log10e" onclick="base10_log(this.form);"></td>
<td><input type="button" value=" log2e " onclick="base2_log(this.form);"></td>


JavaScript provides a Math.log(x) method for calculating the natural (base e) logarithm of x and, given that logb(a) = logd(a) / logd(b), also provides Math.LN10 (ln(10)) and Math.LN2 (ln(2)) constants for converting Math.log(x) returns to common logarithms and binary logarithms, respectively.

A global base_10 variable is set to Math.LN10, and the base10_log( ) function duly divides the natural logarithm of the form.expr.value by base_10 to give a common logarithm - so far, so good.

A global base_2 variable should be set to Math.LN2 but is inexplicably also set to Math.LN10; as a result, the base2_log( ) function's division of Math.log(form.expr.value) by base_2 gives a common logarithm as well. Of course, sorting this matter out is no more difficult than changing var base_2 = Math.LN10; to var base_2 = Math.LN2;.

The calculator doesn't have a key, but it is simple enough to input a Math.log(x) command into the expr field and eval( ) it. Moreover, we can use the logb(a) = logd(a) / logd(b) identity to calculate logarithms for other bases, e.g., to calculate log3(100), just enter and eval( ) Math.log(100) / Math.log(3).

As for the log10e and log2e key labels...

They're kind of confusing, aren't they? I think the "e" may stand for "exponent", which is what a logarithm operation returns, but an "e" on a calculator logarithm key makes me think of e = 2.71828..., and neither of those keys is meant to output a natural logarithm. Much better would be and , yes?

<td><button type="button" onclick="base10_log(this.form);">log<sub>10</sub>(x)</button></td>
<td><button type="button" onclick="base2_log(this.form);">log<sub>2</sub>(x)</button></td>


As shown, the 10 and 2 are subscripted via the sub element, which we can deploy in a <button> label but not in an <input type="button"> label. When the AGSC script went live at Java Goodies at the end of 1997, the current versions of IE and Netscape were IE 4.x and Netscape 4.x, respectively: the button element, with its almost-(%flow;)* content model, is supported (if a bit buggily) by the former but not by the latter. Alternatively, Jamie could have created log10(x) and log2(x) images and put them on <input type="image"> buttons although this strikes me as more trouble than it's worth.

While I'm on this topic, I should note that we can today use numeric character references to put a subscripted 1, 0, and/or 2 in an <input type="button"> label, e.g., <input type="button" name="" value="log&#8321;&#8320;(x)" onclick="base10_log(this.form);"> for , but we couldn't have done so back in 1997.

Mind you, you do also have the option of adding , , , , , and keys and corresponding functions to the AGSC script, but if you don't want to do that, then you have what you need.

We'll go through the trig part of the calculator in the following entry.

Monday, June 13, 2016
 
The Key to the Operation, Part 1
Blog Entry #369

In today's post we tuck into "Another Great Science Calculator", the next Calendars, Clocks, and Calculators (CCC) script. Authored by Jamie Beyore in 1997, the Another Great Science Calculator script codes a desktop calculator via which the user can carry out various mathematical operations, which we will detail in the discussion below.

Visualizing the calculator

The javagoodies.com/scicalc.txt document holding the Another Great Science Calculator script code is still live as of this writing but the script's demo page shows...nothing. As it happens, two incorrectly formulated HTML comments stand in our way.

<!-- In the document head: -->
<!-- The Following Program Was ... (C) 1997 --- //>

<!-- In the document body: -->
<!-- Start Calculator Display --//>


HTML comments should end with a --> character sequence. The head comment contains three alien pre-> characters (the two slashes and the space that precedes them) and the body comment contains two alien pre-> characters (the two slashes); removing these characters brings the display to life.

Jamie's Calculator

This is just an image, not the actual calculator - I'll roll out a functioning demo in due course.

Structure notes

Jamie's calculator is laid out with four tables. Table #1 holds the Jamie's Calculator heading and the display/input field.

<table border="1" valgin="middle" algin="center">
<tr><td bgcolor="yellow" align="center">Jamie's Calculator</td></tr>
<tr><td bgcolor="lightgrey" align="center"><input type="text" name="expr" size="35" action="calculate(this.form);"></td></tr>
</table>


• Misspellings notwithstanding, the table element does not have a valign attribute whereas its align attribute is deprecated. An align="center" setting would horizontally center the table on the page, however; in practice, all of the calculator tables are horizontally centered by a center element (whose required </center> tag is missing).

• "lightgrey" is now a standard, W3C-approved color keyword: its #rrggbb value is #d3d3d3. The bgcolor="lightgrey" setting colors only a 1px cellpadding rectangle, which even the sharpest-eyed observers are unlikely to notice.

• The action attribute is valid for only the form element: it has a %URI; data type and is not used to call functions.

Tables #2-4 frame the calculator's operator and operand keys.
Table #2 holds the row of keys.
Table #3 holds the row of keys.
Table #4 holds the remainder.
The tables #2-4 code is pretty conventional and doesn't contain any red flags (for some keys the onclick setting contains an unnecessary line break but this doesn't cause any problems) so I won't burden you with it.

Could we code the whole shebang as a single table, maybe put the table #1 content in a thead element and/or code the Jamie's Calculator heading as a caption element? Yep, we could do that.

A form element (whose required </form> tag is missing) consolidates the tables and their controls.

<body bgcolor="red" valink="yellow" alink="yellow" link="yellow">
<center>
<form>
...table/input code...


Although there aren't any links in the scicalc.html code, let me lastly point out that the valink in the <body> tag should be vlink.

Operation types

We can organize the calculator operations into four categories:
(A) arithmetic
(E) exponential
(L) logarithmic
(T) trigonometric

(A) For an arithmetic calculation, the user enters an expression containing numbers and one or more operators - e.g., 3 * (5 - 7) / 9 - into the expr field and then clicks the key to display the answer.
(E,L,T) For exponential, logarithmic, and trigonometric calculations, the user enters a number into the expr field and then clicks the applicable operator key to display the answer.
Exception: The reciprocal key, which performs an arithmetic (division) operation, is like the (E,L,T) keys.

Operands and their inputs

The 0-9 digit keys call on an enter( ) function to enter their corresponding digits into the expr field, e.g.:

<head>
<script language="javascript">
...
function enter(arg, string) { arg.expr.value += string; }


<td><input type="button" value=" 7 " onclick="enter(this.form, 7);"></td>

Clicking the key calls enter( ) and passes thereto this.form and 7, which are respectively given arg and string identifiers; subsequently, enter( ) appends string to the value of the arg.expr field.

Inputting a decimal point is a bit different, and is problematic.

var decimalsign = " . ";

<td><input type="button" value=" . " onclick="enter(this.form, decimalsign);"></td>

The script's script element features a top-level section in which a space-dot-space string is assigned to a decimalsign variable; clicking the key appends decimalsign to the arg.expr.value as detailed above. As you would surmise, the spaces in decimalsign shouldn't be there, and they prevent the calculator from carrying out calculations on decimalsign-containing inputs, e.g., pressing returns NaN and not 10. Having said this, I should note that the expr field is an ordinary text input in which we can type values via a computer keyboard, and we do also have the option of inputting an unadorned . character via a . keyboard key. Still, we really ought to get rid of those decimalsign spaces, wouldn't you say?

The key does not convert a number to its additive inverse but instead inputs a negativesign for the purpose of entering a negative number.

// Right after the decimalsign declaration:
var negativesign = " -";


<td><input type="button" value=" neg " onclick="enter(this.form, negativesign);"></td>

Arithmetic

The +, -, *, and / arithmetic operators are also variabilized

// Just before the decimalsign declaration:
var plussign = " + ";
var minussign = " - ";
var multiplysign = " * ";
var dividesign = " / ";


and are enter( )ed into the expr field à la the operand characters.

<td><input type="button" value=" + " onclick="enter(this.form, plussign);"> <input type="button" value=" - " onclick="enter(this.form, minussign);"></td> ...

Left and right parenthesis (( and )) characters are similarly available for overriding the multiplication/division-over-addition/subtraction order of operations.

var leftbracket = " (";
var rightbracket = ") ";


<td><input type="button" value=" ( " onclick="enter(this.form, leftbracket);"></td> <td><input type="button" value=" ) " onclick="enter(this.form, rightbracket);"></td>

Arithmetic expressions are evaluated by a calculate( ) function.

function calculate(arg) { arg.expr.value = eval(arg.expr.value); }

<td><input type="button" value=" = " onclick="calculate(this.form);"></td>

This is a case that really does require the eval( ) function, or at least I can't think of any other way to do what we want to do here.

Multiplicative inverse

A separate inverse( ) function handles the operation.

function inverse(form) { form.expr.value = 1 / form.expr.value; }

<td><input type="button" value=" 1 / X " onclick="inverse(this.form);"></td>

We'll continue our deconstruction of the calculator's functionality in the following entry.


Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)