reptile7's JavaScript blog

Saturday, March 06, 2021

Finger on the Trig

Blog Entry #413

As regards the Super Calculator's

**Special functions**section

we have previously discussed the log, Spec, and PI keys; we'll hit the remaining sin, cos, and tan trigonometry keys in today's post.

Whether logarithm and trigonometry keys are "special" or not is a matter of perspective, I suppose; in my book they are standard calculator functionality, but given that most JavaScript calculators these days don't have them I would seem to be 'outvoted' in this respect. At any rate, I would move the key to the SC's

**Powers**section as it gets the exponent for the e

^{exponent}= power exponentiation and would put the , , and keys in a separate

**Trigonometry**section.

**To the radian**

^{th}degreeClicking the button

`<input type="button" value=" sin " onclick="getinput(sine);">`

initially triggers the

`getinput( )`

function and then a `sine( )`

function`function getinput(func) {`

var a = document.mainform.total; ...

var mode = document.mainform.mode[0].checked ? 1 : 0; ...

if (func == sine) { return sine(mode, a); } ... }

as per usual.

The

`sine( )`

function is the fifteenth-in-source-order function in the supercalc.txt `<script>`

element and closely parallels the `squared( )`

and `cubed( )`

functions, and is detailed below in its entirety (I've spruced it up a bit); Mozilla's current `Math.sin( )`

page is here.`function sine(mode, obj) {`

if (mode == 1) { window.alert("This function returns the sine of any given number."); }

var aa, a;

if (obj.value != "" && obj.value != "0") {

aa = window.prompt("Do you want to find the sine of the number in the total text box?", "y or n");

if (aa == "y") { doit(Math.sin(obj.value), obj); }

else {

a = window.prompt("Enter a number to find the sine of:", "");

more("(" + Math.sin(a) + ")", obj); } }

else {

a = window.prompt("Enter a number to find the sine of:", "");

doit(Math.sin(a), obj); } }

Things go in an equivalent way for the and buttons, which are bound to a

`Math.cos( )`

-based `cosine( )`

function and a `Math.tan( )`

-based `tangent( )`

function, respectively.Can we merge the

`sine( )`

, `cosine( )`

, and `tangent( )`

functions as we did the `squared( )`

, `cubed( )`

, and `power( )`

functions in the previous post, say, via a set of switch statements that handle the help messages and `Math.sin( )`

, `Math.cos( )`

, and `Math.tan( )`

calls? Sure, and I may do just that when I roll out a demo at a later point.Jamie Beyore's Another Great Science Calculator and Saries's Rainbow Calculator also have , , and keys, which for both calculators expect an angle input in degrees, which is reasonable because

(1) a math student first learns about the trigonometric functions in the context of a right triangle and

*then*progresses to their unit circle-based definitions - at least this was true for me back in the day - and

(2) for hand-held calculators having DEG and RAD angular modes, the DEG mode is the default - at least this is true for my trusty Casio fx-85v calculator.

In contrast, the SC's trig keys expect an angle or arc length input in radians, although the

`sine( )`

/`cosine( )`

/`tangent( )`

help messages don't tell the user that.It is simple enough to add a DEG capability to the SC. Drawing inspiration from the help message machinery, we can flank the SC trig buttons with a name="trig_mode" pair ofDEG andRAD radio buttons

`<input type="radio" name="trig_mode" checked="checked" />DEG`

<input type="radio" name="trig_mode" />RAD

and use the trig_mode checked state to control the suitable setting of help messages and angle/arc length inputs, e.g.:

`function sine(mode, obj) {`

var trig_mode, alert_message, aa, a;

trig_mode = document.mainform.trig_mode[0].checked ? 1 : 0; // DEG if true, RAD if false

if (trig_mode) alert_message = "In DEG mode, this function gets the sine of an angle in degrees.";

else alert_message = "In RAD mode, this function gets the sine of an angle/arc length in radians.";

if (mode) window.alert(alert_message);

if (obj.value != "" && obj.value != "0") {

aa = window.prompt("Do you want to find the sine of the number in the total text box?", "y or n");

if (aa == "y") {

a = trig_mode ? obj.value * Math.PI / 180 : obj.value;

doit(Math.sin(a), obj); }

else {

a = window.prompt("Enter a number to find the sine of:", "");

if (trig_mode) a *= Math.PI / 180;

more("(" + Math.sin(a) + ")", obj); } }

else {

a = window.prompt("Enter a number to find the sine of:", "");

if (trig_mode) a *= Math.PI / 180;

doit(Math.sin(a), obj); } }

• Recall that an arc length of

`Math.PI`

radians spans an angle of `180`

degrees.• Note that DEG-RAD bifurcation is needed for each a input point (you can't just bifurcate once at the beginning of the function).

• The *= multiplication assignment operator is detailed here.

Not addressed previously:

Do the

`if (obj.value != "" && obj.value != "0")`

gate and its accompanying `else`

clause serve a purpose here? Getting the sine, cosine, or tangent of 0 degrees or radians is a perfectly legitimate thing to do (unlike getting the of 0, which is not such a perfectly legitimate thing to do); moreover, `Math.sin("")`

, `Math.cos("")`

, and `Math.tan("")`

map the empty string input to 0. You can go ahead and throw out the gate and clause - or not, per your preference.Expressional note:

The

`Math.sin( )`

, `Math.cos( )`

, and `Math.tan( )`

methods balk at (return NaN for) inputs that contain nonnumeric characters, so if you want to get the cosine of (3.141592653589793) radians or the tangent of (3.141592653589793)/4 radians, then you'll have to first get rid of the ( and the ) plus the / by `eval( )`

-uating those inputs via the key and its underlying `calc( )`

function.**Arcsine, arccosine, arctangent**

Now, what if we wanted to go the other way - what if we wanted to map a sine or cosine or tangent to the corresponding angle or arc length - how would we do that?

Neither the SC, Jamie Beyore's calculator, nor Saries's calculator has , , and keys. We noted in the

**Trigonometry**section of Blog Entry #371 that we can get the arcsine, arccosine, or arctangent of a number by typing a relevant JavaScript expression - e.g.,

`Math.acos(-1)`

- into the user input field of Jamie's calculator and then -ing that expression, and we can do the same with the SC and Saries's calculator. However, this is not exactly helpful to users who don't know JavaScript, is it?The , , and keys of my Casio fx-85v calculator have sin

^{-1}, cos

^{-1}, and tan

^{-1}second functions that are accessed via a SHIFT key. Somewhat similarly, the Google calculator widget (this link may or may not take you to the widget, depending on what browser you are using) has an key that toggles the widget's trig keys between // and //.

Of course, we could just add , , and keys to the SC - check out the calculator at Calculator.net - but I like the Google approach better and we'll have a go at applying it to the SC in the following entry.

Sunday, December 27, 2020

Power, Base, and Logarithms

Blog Entry #412

Today's Super Calculator (SC) installment begins with a brief look at an exponentiation-related operation that I've never heard of before...

**Special, or not**

The

**Special functions**section on the left-hand side of the calculator contains a button.

`<input type="button" value="Spec" onclick="getinput(spec);">`

Clicking the button indirectly triggers a

`spec( )`

function whose verbatim**Help**message reads:

`"Spec is handy tool that allows you to multiply a number by another number any number of times. It works kind of like powers, except the only difference is that in powers, you have multiply a number by itself any number of times. This function allows you to multiply any number by any number, any number of times."`

(Would you as a user want to read all that? I wouldn't.)

The

`spec( )`

function carries out an a⋅b^{c}calculation, i.e., it multiplies an a factor by a b factor c times. If you are perchance thinking "

*This is nothing that can't be done with the SC keys we've covered previously*", well, you would be right about that.

Like the other exponentiation functions, the

`spec( )`

function is actually called from the `getinput( )`

function.`if (func == spec) { return spec(mode, a); }`

The

`spec( )`

function is the ninth-in-source-order function in the supercalc.txt `<script>`

element and is similar to the `power( )`

function.It

`prompt( )`

s the user for the a, b, and c operands.A

`d = Math.pow(b, c);`

command raises b to the ^{c}power.

The d = b

^{c}power is multiplied by a.

Depending on the starting point of the calculation, control then passes to either

the

`doit( )`

function so as to set the total.value to the a*d productor

the

`more( )`

function so as to append a (a*d) string to the total.value.**Exponentiation consolidation**

The use of separate functions for the x

^{2}, x

^{3}, and x

^{y}operations is rather inefficient, yes? We can straightforwardly rewrite the

`squared( )`

, `cubed( )`

, and `power( )`

functions as a single function - let's call it `getPower( )`

- if we equip that function with a third, b = 2 or 3 or y parameter for the exponentiation exponent. We can discretely bind the , , and buttons to the `getinput( )`

gateway with simple strings versus the squared, cubed, and power references for the functions we are putting out to pasture.`if (func == "square") { return getPower(mode, a, 2); }`

if (func == "cube") { return getPower(mode, a, 3); }

if (func == "power") { return getPower(mode, a, "y"); }

function getPower(mode, obj, b) { /* getPower( ) body */ }

<button type="button" onclick="getinput('square');">x<sup>2</sup></button>

<button type="button" onclick="getinput('cube');">x<sup>3</sup></button>

<button type="button" onclick="getinput('power');">x<sup>y</sup></button>

The

`getPower( )`

**Help**messages can be gathered and conditionalized via a series of if gates

`var alert_message;`

if (mode) {

if (b == 2) alert_message = "This key allows you to square any given number.";

if (b == 3) alert_message = "This key allows you to cube any given number.";

if (b == "y") alert_message = "This key allows you to raise a base number x to the yth power.";

window.alert(alert_message); }

or a switch statement.

`if (mode) {`

switch (b) {

case 2: alert_message = "This key allows you to square any given number."; break;

case 3: alert_message = "This key allows you to cube any given number."; break;

case "y": alert_message = "This key allows you to raise a base number x to the yth power."; }

window.alert(alert_message); }

(I would prefer to display

`"The xⁿ key allows you to..."`

alert_messages but their rendered exponents are too small for my taste.)For the

`getPower( )`

function's post-help code,just if-gate the exponent

`prompt( )`

s in the relative `power( )`

function codeand you've got what you need:

`var aa, a;`

if (obj.value != "" && obj.value != "0") {

aa = window.prompt("Do you want to use the number in the total text box as the base number?", "y or n");

a = (aa == "y") ? obj.value : window.prompt("Enter a base number:", "");

if (b == "y") b = window.prompt("Enter an exponent:", "");

if (aa == "y") doit(Math.pow(a, b), obj);

else more("(" + Math.pow(a, b) + ")", obj); }

else {

a = window.prompt("Enter a base:", "");

if (b == "y") b = window.prompt("Enter an exponent:", "");

doit(Math.pow(a, b), obj); }

It is left to the reader to integrate the

`spec( )`

function with the `getPower( )`

function, if desired; as intimated above, however, the operation is redundant in my view and I would just as soon send it packing.**Log it**

As regards the z = x

^{y}relation we have calculated

z by raising x to the y

^{th}power and

x by extracting the y

^{th}root of z.

In this section we go after y, the base-x logarithm of z: y = log

_{x}(z).

The

**Special functions**section contains a button (versus a button) for getting the base-e natural logarithm of a number.

Clicking the button effects

an

`onclick="getinput(logrythm);"`

event handler (sic, perhaps the author typed up the code with SimpleText, which does not have a spell checker) and subsequentlyan

`if (func == logrythm) { return logrythm(mode, a); }`

statement in the `getinput( )`

functionà la the exponentiation buttons.

The

`logrythm( )`

function is the fourteenth-in-source-order function in the supercalc.txt `<script>`

element and closely parallels the `squared( )`

and `cubed( )`

functions: it replaces the latter's Math.pow(x, y) commands with Math.log(z) commands and has its own `"This function returns the natural logarythm [sic again] of any given number"`

**Help**message but apart from that their other features (if and if...else gates, variable names,

`doit( )`

and `more( )`

calls) are identical.__Other calculators, other bases__

Jamie Beyore's Another Great Science Calculator features a button for getting the common logarithm of a number and a button for getting the binary logarithm of a number.

Saries' Rainbow Calculator doesn't have any logarithm buttons at all.

Standardly, my Casio fx-85v calculator has a key for getting the common logarithm of a number and a key for getting the natural logarithm of a number.

Meanwhile, back at the SC, why should we limit ourselves to base-e (or base-10 or base-2) logarithms? In the

**Logarithms**section of Blog Entry #370 we noted that we can use the log

_{x}(z) = log

_{e}(z) / log

_{e}(x) change-of-base logarithm formula to get logarithms for bases other than the standard ones. The x

^{y}and log

_{x}(z) calculations both take two inputs, and it occurred to me that the original

`power( )`

function should be easily convertible to a `getLog( )`

function for the latter calculation: all we need to is(1) craft a new

**Help**message (

`"This key allows you to find the logarithm of a number z for the base x of your choosing."`

, something like that),(2) reword the operand

`prompt( )`

s as appropriate (`"Enter an anti-logarithm z:"`

, `"Enter a base x:"`

), and(3) replace the

`Math.pow(a, b)`

commands with `Math.log(a)/Math.log(b)`

commands.Try it out below - re the text box, you can start from or blank the starting 0, or enter your own input - for best results, your z and x choices should be positive numbers other than 1.

__Unreal cases__

Math.log(0) returns -Infinity (rather than undefined).

Math.log(-z) for -z < 0 returns NaN. In the

__You're so square root, baby__subsection of Blog Entry #411 we reached beyond the real number system to take the square root of negative numbers, and we can similarly take the logarithm of negative numbers via the e

^{iπ}= -1 case of the Euler formula.

For the natural log of a negative number

ln(-z) = ln(z) + iπ

whereas for the general base-x case

log

_{x}(-z) = (ln(z) + iπ) / ln(x).

(Btw, Google will calculate the former for you -

`What is the natural log of -47?`- but not the latter.)

I trust that you are up to the task of JavaScripting these expressions.

y = log

_{1}(z) and y = log

_{0}(z) are not meaningful functions: z must necessarily be 1 and 0, respectively, whereas y can be any number.

For the above y = log

_{x}(z) = ln(z) / ln(x) demo

an x = 1 input variously outputs y = Infinity, -Infinity, or NaN whereas

an x = 0 input variously outputs y = 0 or NaN

depending on the z input, e.g., if 1 < z, if 0 < z < 1, etc.

Can the logarithm base x itself be negative?

The answer is basically yes, but it's not generally very useful- let's leave it at that.

We'll discuss the SC's trig functions in the next entry.

Friday, July 24, 2020

A Whole or Fractional

`power( )`

Blog Entry #411

We return now to our run through the Super Calculator's exponentiation landscape. With all that

`prompt( )`

ing in the `power( )`

, `squared( )`

, and `cubed( )`

functions, it occurred to me that we should talk about the a and b data types a bit before we go any further...**x**

^{y}input auditFor our 9

^{7}exponentiation in the previous post, the a = 9 and b = 7 inputs actually have a string data type: at

`Math.pow(a, b)`

time, the 9 and 7 operands are converted to numbers.__"" and null__

If we leave a

`prompt( )`

inputDefault field blankand click the button, then the

`prompt( )`

output is the empty string; if we click the button, then the output is null (the primitive value vs. as a string). When plugged into a `Math.pow( )`

command, "" and null both convert to 0. FYI: `Math.pow(0, 0)`

returns 1 even though 0^{0}has

no agreed-upon value.

__Non-empty, non-numeric__

Suppose we type hello in the total field (the total field is not readonly, we can do that) and try to raise it to the

^{world}power: as you would expect, hello

^{world}returns NaN. Such inputs can be intercepted via an iterative

`isNaN( )`

test (admittedly at the risk of annoying the user), e.g.:`b = window.prompt("Enter an exponent:", "");`

while (isNaN(b)) { b = window.prompt("Your exponent must be a number:", ""); }

__π__

In the

**C/d**section of Blog Entry #409 we learned that the SC's key outputs a Math.PI.toFixed(15) value surrounded by parentheses. The ( and ) characters prevent the conversion of the (3.141592653589793) string to a number for an exponentiation (or trigonometric) operation; as a result,

`Math.pow("(3.141592653589793)", b)`

returns NaN for all b except b = 0, for which the return is 1. We can easily lose the ( ) by pressing the key, i.e., `eval("(3.141592653589793)")`

returns 3.141592653589793 (as a number, which is stringified when written to the total field), after which we can raise the pi value to whatever power we want.**Root extraction**

Root extraction can be expressed exponentially: finding the y

^{th}root of some number x is equivalent to raising x to the

^{1/y}power.

We can use the original

`power( )`

function to calculate a x^{1/y}root as long as the

^{1/y}exponent is in

*decimal*form: b = 0.5 for a square root, b = 0.25 for a 4

^{th}root, etc. As you would intuit from the preceding (π) discussion, a 1/y string's / character prevents its

`Math.pow( )`

numberification.If we don't know 1/y's decimal equivalent, then we can divide 1 by y in advance, copy the quotient to the clipboard, and paste the quotient into the

`Enter an exponent:`

inputDefault field when the time comes. As it happens, however, any numerator/denominator-type fraction can be `eval( )`

ed to its decimal equivalent - cf. the SC's `calc( )`

function - so if we insert an`if (/^1\/\d+$/.test(b)) b = eval(b);`

statement* after each`b = window.prompt("Enter an exponent:", "");`

statement,then we can input 1/y itself into the inputDefault field.

*The /^1\/\d+$/ regexp pattern matches a 1/y string whose y character is an unsigned integer; we'd need a more complex pattern to additionally accommodate other ys.

So now, if we want to find the 7

^{th}root of 9 (maybe you would know that 1/7 = 0.14285714285714285, but I wouldn't), we're all set.

My Casio fx-85v calculator has an x

^{1/y}function, which is accessed via SHIFT-ing the key. We have the option of putting a image on a push button:

`<button type="button" onclick=""><img width="" height="" style="" src="pathname/yth_root_of_x2.gif" alt="" /></button>`

In creating the yth_root_of_x2.gif image, I gave the x and y a 16px/13px default/

`<sup>`

font-size ratio.__You're so square root, baby__

The SC's

**Misc**section has a dedicated button

`<input type="button" value="Sqrt" onclick="getinput(squareroot);">`

for getting the square root of a number. The button is bound to a

`squareroot( )`

function that is called from the `getinput( )`

function à la the `power( )`

, `squared( )`

, and `cubed( )`

functions.`if (func == squareroot) { return squareroot(mode, a); }`

The

`squareroot( )`

function is detailed below; Mozilla's current `Math.sqrt( )`

page is here.`function squareroot(mode, obj) {`

if (mode == 1) { window.alert("This function gives you the square root of any given number"); }

if (obj.value != "" && obj.value != "0") {

aa = window.prompt("Do you want to find the square root of the current number in the total text box?", "y or n");

if (aa == "y") { doit(Math.sqrt(obj.value), obj); }

else {

a = window.prompt("Enter a number to find the square root of:", "");

more("(" + Math.sqrt(a) + ")", obj); } }

else {

a = window.prompt("Enter a number to find the square root of:", "");

doit(Math.sqrt(a), obj); } }

I gave you a detailed

`power( )`

deconstruction earlier, do we need to do the same thing here? Nah, let's go with a quick post-mode rundown:(1) If the total.value isn't empty or 0 - if we've entered

*something*into the total field, not necessarily a number - then we are

`prompt( )`

ed to confirm (`y or n`

) that we want to square-root the entered value.(a) If y, then the total.value is square-rooted and the resulting square root is written to the total field via the

`doit( )`

function.(b) If not y, then we are

`prompt( )`

ed for a new value to square-root; the a `prompt( )`

output is square-rooted and (a^{1/2}) is appended to the total.value via the

`more( )`

function.(2) If the total.value

*is*empty or 0, then we are

`prompt( )`

ed for a value to square-root; the a `prompt( )`

output is square-rooted and a^{1/2}is written to the total field via the

`doit( )`

function.If the SC's mode help flag is turned on (1), then we'll get a

`This function gives you the square root of any given number`

`alert( )`

messagebefore the if tests and

`prompt( )`

ing get under way. The message could be a bit more specific: we all know that we can't take the square root of a negative number...*or can we?*Actually, we addressed the calculation of imaginary square roots in the

__It's complex__section of Blog Entry #344 during our analysis of the CCC Quadratic Equation script; for the SC the corresponding code could go something like:

`var radicand = Number(x); // x = obj.value or a`

if (radicand < 0) {

var real_root = Math.sqrt(-radicand);

var imag_root = "i \u00d7 " + real_root;

obj.value = imag_root;

return; }

Otherwise,

`Math.sqrt(x)`

returns NaN if x cannot be converted to a nonnegative number;per the

__Non-empty, non-numeric__subsection above,

a

`while (isNaN(x) || x < 0) { x = window.prompt("Your radicand must be a nonnegative number.", ""); }`

-type statementcan be used to intercept problematic

`Math.sqrt(x)`

inputs.Apropos asides:

Jamie Beyore's Another Great Science Calculator has a key that executes

an external

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

function whereasSaries's Rainbow Calculator has an (unsuperscripted) key that executes

an inline

`document.calculator.text.value = Math.sqrt(document.calculator.text.value)`

statement.A standard calculator won't calculate imaginary square roots (at least my Casio won't), but if you go to Google and enter

`What is the square root of -9?`

in the search field and then click your keyboard's Enter/Return key, you'll get a new page with a

`square root(-9) = 3i`

div near the top of it.

We'll cover the SC's and functionality in the following entry.

Thursday, June 25, 2020

And You, Be Ye Fruitful, and Exponentiate

Blog Entry #410

In the

**Arithmetic action**section of the previous post we used the Super Calculator to add 9 and 7. As we can all add 9 and 7 in our heads without the aid of a calculator, let's up our game by using the SC to raise 9 to the 7

^{th}power.

**9**

^{7}We enter a 9 into the total field via the button and the

`more( )`

function as described earlier. We click the button in the SC's **Powers**section

`<td><b>Powers:</b><br>`

...

<input type="button" value=" x^y " onclick="getinput(power);">

thereby calling the

`getinput( )`

function and passing thereto a power function reference. I'm not going to put the entire `getinput( )`

function in front of you (see the whole thing here); the relevant part of it for our present purpose is:`function getinput(func) {`

var a = document.mainform.total;

if (document.mainform.mode[0].checked) { var mode = 1; } // Help mode

else { var mode = 0; } // Non-help mode

if (func == power) { return power(mode, a); } ...

The power argument is given a func identifier.

The total Text object is assigned to an a variable - how's that for a descriptive name? - I'd call it calcText or something like that.

A mode variable is set to 1 if the

**Help**radio button is checked or to 0 if the

**No Help**radio button is checked; a conditional (ternary)

`var mode = document.mainform.mode[0].checked ? 1 : 0;`

statement can be used here.The

`<script>`

's `power( )`

function is called if func and power are equal - true in this case.Here is the

`power( )`

function from start to finish:`function power(mode, obj) {`

if (mode == 1) { window.alert("Power allows you to give powers to any given number."); }

if (obj.value != "" && obj.value != "0") {

aa = window.prompt("Do you want to use the number in the total textbox as the base number?", "y or n");

if (aa == "y") { a = obj.value; }

else { a = window.prompt("Enter a base number:", ""); }

b = window.prompt("Enter an exponent:", "");

if (aa == "y") { doit(Math.pow(a, b), obj); }

else { more("(" + Math.pow(a, b) + ")", obj); } }

else {

a = window.prompt("Enter a base:", "");

b = window.prompt("Enter an exponent:", "");

doit(Math.pow(a, b), obj); } }

The mode number and the a object are passed to the

`power( )`

function and are given the identifiers mode and obj, respectively.The

`power( )`

function checks if the mode help flag is turned on (it's initially on, as was noted earlier, although you are free to turn it off, of course) and if so displays a`Power allows you to give powers to any given number`

`alert( )`

message.The author/Webmaster sees the [p]ower identifier but the user doesn't, and I would recast the message as:

`The x^y key allows you to raise a base number x to the yth power.`

The

`power( )`

function testsif the obj.value is not the empty string AND (&&)

if the obj.value is not the numeric string

`"0"`

and if both conditions are met - our 9 fits the bill, yes? - displays a

`prompt( )`

box that asks us if we want to use the number in the total field for the x base number, which strikes me as an odd sort of thing for a calculator to do, but that's what happens.(Now that I think about it, this sort of message belongs on a

`confirm( )`

box.)As shown above, the default value of the

`prompt( )`

input field (termed the inputDefault back in the day) is set to a `y or n`

string. Some browsers (e.g., Firefox/Netscape, Opera, Safari) select the string: if we're using such a browser, then we can convey our 'yes' by simply pressing the keyboard's `y`key. The y value is assigned to an aa variable upon clicking the prompt's button.

The

`power( )`

function tests if aa is y - true - and then assigns the obj.value, 9, to an a variable: this a has a global scope because it is not declared with the var keyword (ditto for the above aa variable and the b variable below) and it is wholly distinct from the `getinput( )`

function's a, which is declared with the var keyword and is therefore local to the `getinput( )`

function, not that it would make a difference if the former a superseded the latter a.The

`power( )`

function displays a `prompt( )`

box that instructs us to enter an exponent, so we type a 7 in the `prompt( )`

input field. The 7 value is assigned to a b variable upon clicking the prompt's button.The

`power( )`

function again tests if aa is y - still true - and thenexponentiates a to the b

^{th}power via the

`pow( )`

method of the Math object andsends the a

^{b}power, 4782969, and the obj reference for the total field to the

`doit( )`

function,which we discussed in the

**Roundabout rounding**section of the previous post and

which writes the a

^{b}power (renamed obj by the

`doit( )`

declaration) to the total field (renamed where by the `doit( )`

declaration).We're not quite done yet. Moving back to the

`getinput( )`

function, note that the `power( )`

call is preceded by a return keyword, which causes the browser to exit the `getinput( )`

function after the `power( )`

function has finished executing. (The aforediscussed `doit( )`

call is neither preceded nor followed by a return keyword, and the `power( )`

function returns undefined to the `getinput( )`

function.)__Two other__

`power( )`

possibilities, brieflyIf the obj field holds the starting 0 or has been backspaced to a blank,

then the

`power( )`

function will`prompt( )`

us for a base (a),`prompt( )`

us for an exponent (b), andraise a to the b

^{th}power and load the a

^{b}power into the where field via the

`doit( )`

function as described above.If we do not answer y to the

`Do you want to use the number in the total textbox as the base number?`prompt

(leaving the

`y or n`

inputDefault in place counts as not answering y),then the

`power( )`

function will`prompt( )`

us for a base number (a),`prompt( )`

us for an exponent (b), andraise a to the b

^{th}power and wrap the a

^{b}power in parentheses and ship the (a

^{b}) string and the obj reference to the

`more( )`

function, whose else clause will *append*the (a

^{b}) string to whatever is present in the total field.

→

Got all that? Quite a bit more involved than the corresponding

`function raisePower(x) {`

var y = 0;

y = window.prompt("What is the exponent?", "");

document.calculator.text.value = Math.pow(x, y); }

in Saries's Rainbow Calculator script, isn't it?

**Squaring and cubing**

We can use the button to raise a base number to the 2

^{nd}or 3

^{rd}power; however, the

**Powers**section has dedicated and buttons

`<input type="button" value=" ^2 " onclick="getinput(squared);">`

<input type="button" value=" ^3 " onclick="getinput(cubed);">

for these operations. The and buttons are bound respectively to

`squared( )`

and `cubed( )`

functions that are called from the `getinput( )`

function à la the `power( )`

function`if (func == squared) { return squared(mode, a); }`

if (func == cubed) { return cubed(mode, a); }

and that are largely analogous to the

`power( )`

function, more specifically, they're a bit simpler than `power( )`

in that they don't need to get an exponent from the user.**Exponentiation button labels, revisited**

A coder will know that the ^ symbols signify exponentiations, but will an ordinary user know that? The

**Powers**heading and the

**Help**help messages are not an adequate substitute for seeing actual exponents on the

**Powers**buttons, in my opinion.

__The button exponent blues, at least for Netscape__

The Latin-1 Supplement Unicode block contains a ² superscript two character and a ³ superscript three character, whose HTML numeric character references are ² and ³, respectively. I find that Navigator 4.05 (recall the SC's

best used with Netscape Communicator 4.0metatext) will not render these characters, e.g., it renders

`<input type="button" value="x³">`

as versus . Meanwhile, the Spacing Modifier Letters Unicode block contains a ʸ superscript y character (ʸ, thanks, Rupert); as you might guess, Navigator 4.05 won't render that one either.• Level 4 and earlier browsers will display most of the 'upper Latin-1' characters - ©, é, ü, ÷, ... - but they can't handle the ² and ³ or can't quite handle them, e.g., IE 4.5 displays them as normal 2 and 3 characters and not as superscripts.

• The ², ³, and ʸ characters all appeared in Unicode 1.0.0, the very first version of Unicode, which went live in October 1991.

At the beginning of Blog Entry #75 I mooted the use of graphical submit buttons for calculator keys whose labels feature uncodable symbols - would this approach have worked for the

**Powers**buttons way back when? I accordingly create

an x_to_the_yth.gif image

(I clip it from a screen shot, Netscape 4.x's buttons have a #dddddd background color)

and buttonize it via

`<input name="power_gsb" type="image" src="x_to_the_yth.gif" onclick="getinput(power);">`

.In the event:

With Navigator 4.05, clicking the power_gsb button does not trigger the

`getinput( )`

/`power( )`

code but it does cause the mainform form to submit; the latter action can be choked off by giving the form an `onsubmit="return false;"`

attribute.With IE 4.5, the power_gsb button is invisible until I give it some sort of styling* - even an otherwise effectless

`style="display:inline;"`

will do - but upon doing that and clicking the button, the `getinput( )`

/`power( )`

code runs without incident. (*I don't know if this is a browser/plug-in bug or an artifact of my SheepShaver setup - this page makes me suspect the former.)• The

`<input type="image">`

element has no reflection in classical JavaScript; it should map to the Submit object, but it doesn't. Btw, an `<input type="submit" value="x^y" onclick="getinput(power); return false;">`

button works just fine.Of course, we would today deploy

`<button type="button">x<sup>n</sup></button>`

buttons in the **Powers**section. Navigator 4.05 supports the sup element but not the button element; IE 4.5 supports both elements.

__A buttonless workaround__

The following code works with Navigator 4.05 and IE 4.5 and also with Navigator 3.04 and Communicator 4.61 and IE 5.1.7 and modern browsers:

`<a href="" onclick="getinput(power); return false;" style="display:inline;"><img width="21" height="18" border="1" src="x_to_the_yth.gif" alt=""></a>`

A graphical submit button may be a problematic onclick carrier, but there are no problems with a corresponding link carrier. As a general rule, I don't like to use a link for a non-linking purpose, but a coder's gotta do what a coder's gotta do, eh?

• The link href is set to an empty string, which would normally cause a page reload when we click the link-image, but we can stop that from happening with a return false too.

• Per the preceding subsection, the

`style="display:inline;"`

is for IE 4.5's benefit; none of the other browsers needs it.• Attaching the

`style="display:inline;"`

to the `<img>`

element gives rise to some bizarre image-moving behavior with Navigator 4.05 and Communicator 4.61 - I'll spare you the details.• A

`style="position:relative;"`

visualizer, which should also be effectless, causes Navigator 4.05 and Communicator 4.61 to crash.
There are actually three other SC keys that relate to exponentiation - , , and - and we'll discuss them and their underlying

`function`

s in our next episode.Monday, April 27, 2020

SC II

Blog Entry #409

OK, let's get back to our discussion of the CCC Super Calculator; we are at present ready to segue from structure to behavior by taking on the SC's JavaScript.

The supercalc.html

`<script>`

code comprises no fewer than *twenty-five*functions. A sprawling

`getinput( )`

function at the top of the script serves as a gateway to seventeen of those functions. Outside `getinput( )`

's jurisdiction are `more( )`

, `calc( )`

, `cleart( )`

, `less( )`

, `helppi( )`

, `doit( )`

, and `helpround( )`

functions that are relevant to the __Arithmetic__and

__remainder__parts of the calculator and that we will cover in today's post.

**Arithmetic action**

Suppose we want to add 9 and 7. We click the calculator's button

`<input type="button" value=" 9 " onclick="more(9, document.mainform.total);">`

thereby calling a

`more( )`

function.`function more(obj, where) {`

if (where.value == "" || where.value == "0") { where.value = obj; }

else { where.value += obj; } }

The number 9 and a

`document.mainform.total`

object reference for the total I/O text field`<input type="text" name="total" size="20" value="0">`

are passed to the

`more( )`

function and are given the identifiers obj and where, respectively. If the `where.value`

is the empty string* or the numeric string `"0"`

- true in this case - then it is set to obj; if a non-0 value were already present in the where field, then obj would be appended to that value.*The starting

`"0"`

, or any inputted value, can be backspaced to a blank.• As for a standard calculator, the total.value is initialized to 0.

• Usually, the user display for a standard calculator is right-justified; Netscape 4.x won't

`text-align:right;`

the total field but modern browsers will.• FYI, the default size for an

`<input type="text">`

is 20. If the SC had a lot of text boxes with a size="20" attribute, then I would delete those attributes, but just one? Leave it.→ →

Clicking the and buttons similarly calls the

`more( )`

function and appends + and 7 characters to the 9 per `more( )`

's else clause.To calculate and display the sum, we click the button

`<input type="button" value=" = " onclick="calc(document.mainform.total, document.mainform.total);">`

thereby calling a

`calc( )`

function.`function calc(obj, objw) {`

if (objw.value == "") { objw.value = ''; }

objw.value = eval(obj.value); }

The

`calc( )`

call strangely passes *two*

`document.mainform.total`

references to the `calc( )`

function: the arguments[0] argument is given an obj identifier and the arguments[1] argument is given an objw identifier. The `calc( )`

function `eval( )`

s the `obj.value`

and then parks the result in the objw field.→

Prior to carrying out the sum,

`calc( )`

tests if the `objw.value`

is an empty string: if true, then the `objw.value`

is pointlessly reset to an empty string.Is there any need to use two Text objects here? If there is, I don't see it. Moreover,

`eval('')`

returns undefined with all of the browsers on my computer: a blank should be converted to a 0 for this case. I would consequently rewrite the `calc( )`

function as:`function calc(obj) { if (! obj.value.length) obj.value = 0; obj.value = eval(obj.value); }`

I should lastly note that we can also get the sum by typing

`9+7`in the total field and clicking the button as the total field is not readonly (the readonly attribute was standardized in HTML 4, which postdates the SC).

__More arithmetic__

`more( )`

buttons and the additive inverse buttonClicking the other digit buttons,

the decimal point button,

the other arithmetic operator buttons,

and the parentheses buttons

loads the corresponding characters into the total field via the

`more( )`

function as described above.The additive inverse button is bound to a separate

`negpos( )`

function that we will discuss at a later point.**C/d**

The button

`<input type="button" value=" PI " onclick="helppi( ); more('(' + Math.PI + ')', document.mainform.total);">`

also calls on

`more( )`

in order to load π into the total field although the details are a bit different. Clicking the button first calls a `helppi( )`

function`function helppi( ) {`

if (document.mainform.mode[0].checked) { window.alert("PI is an easy function that just gives you PI. 3.14......"); } }

that pops up a

`PI is an easy function that just gives you PI. 3.14......`message

if the

**Help**radio button is checked, as is true initially.

`<b>Mode:`

<input name="mode" type="radio" checked>Help

<input name="mode" type="radio">No Help

<!-- No </b> is present in the source. -->

Subsequently, a '(3.141592653589793)' string - yep, 15 fractional digits - is shipped off to

`more( )`

. I think the parentheses are there to prevent the π value from being appended to an already-present preceding number.→

JavaScript (the browser's JavaScript engine) does not see 5(3.141592653589793) as a multiplication, however; you'll have to input an * symbol between the 5 and the (3.141592653589793) to calculate the circumference of a circle whose diameter is 5. In practice,

`eval('5(3.141592653589793)')`

throws a `5 is not a function`TypeError.

My Casio fx-85v calculator outputs π to seven places past the decimal point (3.1415927), which is

*good enough*for me, and therefore I would send

`Math.PI.toFixed(7)`

to `more( )`

instead.**Clearing and backspacing**

Clicking the SC's button calls a

`cleart( )`

function that clears the total field by resetting it to 0 à la a standard calculator.`function cleart(obj) { obj.value = "0"; }`

<input type="button" value=" C " onclick="cleart(document.mainform.total);">

Clicking the SC's button calls a

`less( )`

function that backspaces the total.value; like a standard calculator's (clear entry) button, the button allows the user to delete the rightmost number of a larger expression without having to start over.`function less(obj) { obj.value = obj.value.substring(0, obj.value.length - 1); }`

<input type="button" value=" <-- " onclick="less(document.mainform.total);">

I don't like the button's label or location:

I'd relabel it (no dashed arrows, please)

and put it next to the clearing button as Saries's Rainbow Calculator does.

FWIW, my Casio fx-85v has a backspace button that will backspace an inputted value but not an outputted value, e.g., upon dividing 10 by 7, it won't backspace the 1.4285714 quotient; in contrast, the

`less( )`

function backspaces *all*total.values.

**Roundabout rounding**

Twelve of the

`getinput( )`

-gated functions call on an external `doit( )`

function to overwrite the total.value with a new obj value.`function doit(obj, where) { // For all cases, where = document.mainform.total`

where.value = obj; }

The SC's button for rounding a non-integer to an integer also calls on the

`doit( )`

function.`<input type="button" value="Round" onclick="helpround( ); doit(Math.round(document.mainform.total.value), document.mainform.total);">`

As shown above, the rounding is carried out by a

`Math.round(document.mainform.total.value)`

operation embedded in the `doit( )`

call. The `round( )`

ed output is passed to `doit( )`

as the arguments[0] `doit( )`

argument and then is written to the total field.Perhaps you are thinking, "The

`cleart( )`

and `less( )`

functions have just one parameter. Why don't we send `document.mainform.total`

to a dedicated `function roundValue(obj) { obj.value = Math.round(obj.value); }`

function instead?" Well, that would be a more straightforward way to go, wouldn't it?Prior to the

`doit( )`

call the button calls on a `helpround( )`

function`function helpround( ) {`

if (document.mainform.mode[0].checked) { window.alert("Round is an easy function that simply rounds the number in the total textbox to the nearest whole number."); } }

that pops up a

`Round is an easy function that simply rounds the number in the total textbox to the nearest whole number`message

if the

**Help**radio button is checked. The term "whole number"

*generally*means 0 or a positive integer but not a negative integer (although some people use "whole number" and "integer" interchangeably), so we should probably change

`whole number`

to `integer`

in the `alert( )`

text as the `round( )`

method duly rounds negative numbers as well as positive ones.
We'll go after the SC's exponentiation and trigonometry operations in the following entry.

Friday, April 03, 2020

Super Calc v2.3

Blog Entry #408

The next Calculators, Calendars, and Clocks item is a Super Calculator ("SC" hereafter), which went live at Java Goodies in September 1997 and was created by Tom Richardson, Jr. The SC code is posted here.

We've covered a JavaScript calculator twice previously.

(1) Blog Entries #74 and #75 go through Saries's Rainbow Calculator.

(2) Blog Entries #369, #370, and #371 go through Jamie Beyore's Another Great Science Calculator.

The SC is operations-wise similar to these calculators; it has some features that they don't have - e.g., it provides a memory facility and an extensive

`alert( )`

-based help system - and vice versa.**Super structural summary**

__Set the controls for the heart of the calculator__

The SC includes 47 controls in total, they being

a name="total" I/O text field,

41 push buttons for the various input and operation keys plus a push button for an About feature near the bottom of the calculator,

two hidden fields for memory inputs, and

two radio buttons for turning its help system on and off, respectively.

These controls are accessed (and were rendered back in the day) via a containing name="mainform" form.

The mainform form content includes the tables and outro material described below, and is horizontally centered on the page by an unclosed

`<center>`

element. Here's a screen shot of the original supercalc.txt → supercalc.html display:__Lay of the land__

The SC display is laid out with

*six*borderless tables.

`var tables = document.forms["mainform"].getElementsByTagName("table");`

The tables[0] table holds the big Super Calc v2.3 heading and the Best used with Netscape Communicator 4.0 metatext.

The tables[1] table holds the business end of the calculator in its entirety - everything between the Best used with Netscape Communicator 4.0 text and the button - and itself serves as a container for the tables[2]-tables[5] tables.

The tables[2] table holds the

**Scientific Notation**,

**Memory**, and

**Special functions**sections on the left-hand side.

Moving to the middle, the tables[3] table holds the

**Mode**radio buttons and the 0-defaultValued total field and the key whereas the tables[4] table holds the ... keys.

Lastly, the tables[5] table holds the

**Powers**,

**Finding "x"**,

**Fractions**, and

**Misc**sections on the right-hand side.

I am normally lenient as regards leaving

`<table>`

markup in place for these old scripts, but it would clearly be stretching it to say that we are dealing with grids of data in this case: the tables can and should be exchanged for an equivalent set of divs.**Intro, horizontality, key headings**

The Super Calc v2.3 heading is actually coded with a font element:

`<font color="red" size="6"><b><center>Super Calc v2.3</b></font>`

<!-- Nope, there's no </center> tag here either. -->

As it happens, the size="6" setting and an h1 element both give a 32px font-size, so we can more appropriately code the heading with:

`h1 { color: red; text-align: center; }`

<h1>Super Calc v2.3</h1>

An h1 heading provides a

`<p>`

-like separation between the heading and the Best used with Netscape Communicator 4.0 text; as shown by the above screen shot, the font formulation puts the heading and the text in the same line box (Joe's /JSBook/supercalc.html demo inserts a `<br>`

between them).The Netscape Communicator 4.0 link points to an http://cgi.netscape.com/cgi-bin/upgrade.cgi resource, which is no longer live (you wouldn't expect it to be) although archived versions of it are still available, not that we want to be encouraging Netscape Communicator 4.0 use in this day and age, of course.

The tables[1] table horizontally separates the tables[2] table, the tables[3]-tables[4] tables, and the tables[5] table via a cellspacing="20" attribute. If we give the tables[1] table → div an id="calcDiv" and contain the tables[3]-tables[4] controls with a single div, then we can approximately reproduce the horizontal separation via a

`#calcDiv div { display: inline-block; margin: 10px; }`

styling.The

**Scientific Notation**,

**Memory**, ... headings are not put in

`<th>`

cells but are simply `<b>`

olded. Alternatively, we can legitimately mark up the headings with the label element:`label { display: block; font-weight: bold; margin: 2px; }`

<div id="calcDiv">

<div>

<label>Scientific Notation:<br />

<input type="button" value="Scie" onclick="getinput(scie);" />

<input type="button" value="UnScie" onclick="getinput(unscie);" />

</label> ...

**Outro**

The SC display concludes with some 'fine print' - I'll call it that as it's wrapped in a

`<font size="-50">`

element whose size="-50" setting gives an x-small font-size.The fine print's first line warns us:

Note: This script is NOT compatible with Microsoft's Internet Explorer 3.0

`<font color="red"><blink>Note: This script is NOT compatible with Microsoft's Internet Explorer 3.0</font></blink><br>`

We learned a couple of entries ago that IE 3.01 for the Mac won't act on onclick commands, which come up aplenty in the supercalc.html source; I have no idea what problem(s) may arise on the Windows side. The warning is reddened by a font element and is also marked up with a blink element (note that the font and blink elements are improperly nested), which does cause it to blink with the various versions of Netscape on my computer but is not supported by modern browsers. If this were a

*genuinely important*message, then maybe we would blink it by toggling its visibility between visible and hidden, but it clearly isn't.

The fine print's second line asserts:

"[The SC is] the most powerful Web-based calculator in the world."

Perhaps this was true at the time of posting, and it's a boast that holds up surprisingly well today in that

*most modern-day JavaScript calculators do not venture beyond basic arithmetic*- don't take my word for it, run a javascript calculator Google search and see for yourself.

The fine print's third and last line is a

*by Tom Richardson Jr.*authorship credit. The Tom Richardson Jr. link points to an http://home.rmci.net/gooftroop resource, which is not available (if it ever was). The credit is approximately right-justified via 40 preceding spaces (36 s, 4 newlines).

Atop the fine print is an button that when clicked pops up an 'IP notice':

`Super Calc v2.3(R) with new more compact Equasion+(R). Both Copyright(C) and authored by Tom Richardson Jr of Richardson Technologies(R)`

`<input type="button" value="About" onclick="window.alert('Super Calc v2.3(R) with new more compact Equasion+(R). Both Copyright(C) and authored by Tom Richardson Jr of Richardson Technologies(R)');">`

• For an

`alert( )`

message or any other JavaScript string, an ® registered trademark symbol can be coded with \u00ae and a © copyright symbol can be coded with \u00a9.Try it out:

**Operational overview**

__Arithmetic__

Like all calculators, the SC can add, subtract, multiply, and divide.

It has a additive inverse key but not a reciprocal key.

It doesn't have a percent key or a modulo key.

__Exponentiation, square root, logarithm__

The SC has and keys for squaring and cubing a number; moreover and more generally, it has an key for raising a number to the y

^{th}power.

It has a key for calculating the square root of a number; it doesn't have a key for calculating the y

^{th}root of a number.

It has a key for calculating the

*natural*logarithm of a number; it doesn't have a key for calculating the common logarithm of a number.

__Trigonometry__

The SC has , , and keys for calculating the sine, cosine, and tangent of an angle in

*radians*.

__General__

The SC has an key for

`eval( )`

uating an expression in the total field.It has a key for clearing the total field and also a backspace key for deleting the total.value's rightmost character.

It has and parentheses keys that can be used to circumvent the MDAS (×/÷ over +/-) order of arithmetic operations.

__Memory__

The SC has and memory in (M+) keys and corresponding and memory recall (MR) keys and an memory clear key.

__The remainder__

The SC has a key for inputting π (3.14159...).

It has a key for rounding a number with a fractional part to the nearest integer.

Finally, it has , , , , and keys for operations that are, shall we say, 'off the beaten track' for a calculator - we'll detail them later.

**Operational details**

We'll do this next time.

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