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.

Comments: Post a Comment

<< Home

Powered by Blogger

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