reptile7's JavaScript blog
Saturday, February 25, 2023
Memory Coda and Most of the
scie( )
Function StoryBlog Entry #418
I've got a bit more to say about the memory business before moving on...
Toward a more normal memory
Like the Super Calculator and its and keys, my handheld Casio fx-85v calculator has a key for basic memory input, although the two calculators have different post-memory behaviors, namely,
upon inputting a first number and copying it to memory and then inputting a second number,
the Casio overwrites the first number in the display field with the second number -
pressing and then and then gives a 7 display - whereas
the SC appends the second number to the first number in the total field -
pressing and then and then gives a 97 total value.
I prefer the Casio behavior to that of the SC and would sync the latter with the former via a meminput global boolean flag as per our approach to an M+ capability in the previous post. Accordingly, the
more( )
function that controls the total display becomes:var meminput = 0, memplus = 0;
function more(obj, where) {
/* If the meminput or memplus flag was switched to 1 by the getinput( ) function, then a new input replaces a preceding input. */
if (where.value == "" || where.value == "0" || meminput || memplus) where.value = obj;
/* If both flags are 0, then a new input is appended to a preceding input. */
else where.value += obj;
/* meminput or memplus must be turned off for a new input having more than one character. */
if (meminput) meminput = 0; if (memplus) memplus = 0; }
• You might prefer the original SC behavior if you wanted to do some arithmetic on the first number after memorizing it.
• Not mentioned previously: I named the M+ flag memplus and not mem+ because a JavaScript identifier cannot contain a + symbol.
My Casio also has an key and an M- function that is accessed by SHIFT-ing the key, and a sequential use of the key, the key, and the M- function clearly indicates that they all interact with a common hidden field.
In the previous post we converted the SC's key to an key
but if we alternatively add a new key and leave the key in place
then both controls will act on the memory2 field à la the Casio and
we can similarly add a new key that does so as well.
function getinput(func) { ...
if (func == "mem-") { memminus = 1; return mem(mode, a, c); } ... }
var meminput = 0, memplus = 0, memminus = 0;
...updated mem( ) and more( ) code...
<button type="button" onclick="getinput('mem-');"> M- </button>
As a power of 10
Just above the SC's Memory section - at the top of its tables[2] table - is a Scientific Notation section.
Scientific Notation:
The key calls on a
scie( )
function to express a standard form number in scientific notation, e.g., it'll convert 2023 to 2.023*10^3. The "standard form" and "scientific notation" number descriptors evidently have different definitions in the US and in the UK - I'll use their American definitions in the discussion that follows. Complementarily, the key calls on an unscie( )
function that solicits the user for the "decimal" (coefficient) and the "power that is given to 10" (exponent) of a scientific notation number and then outputs the corresponding standard form number.Standard to scientific
The
scie(mode, obj)
function is calledand equipped with mode = 1|0 and obj = document.mainform.total arguments
by the
getinput(func)
function in the usual manner.(See the complete, unabridged SC code for the full details.)
A switched-on mode effects the display of an
alert( )
help pop-up whose message reads:Scie is [a] cool function that allows you to convert any given number into scientific notation. The format of the answer is as follows: Ex: input:120, output:1.2*10^2, would be 1.2 multiplied by 10 to the second power.
Next, the user is
prompt( )
-queried for a number to express in scientific notation - you know the drill:if (obj.value != "" && obj.value != "0") {
aa = window.prompt("Do you want to convert the current number in the total text box?", "y or n");
if (aa == "y") a = obj.value;
else a = window.prompt("Enter a number to convert:", ""); }
else a = window.prompt("Enter a number to convert:", "");
The standard form number input is given an a identifier
and is converted into scientific notation by the following code:
var b = 0;
while (a > 10) { // Divide by ten until variable is no longer greater than 10
a /= 10;
b += 1; }
A while loop iteratively divides a by 10 until a is less than or equal to 10. Meanwhile, a b counter counts up the number of divisions and will subsequently serve as the exponent in the final output.
Lastly, a
doit(a + "*10^" + b, obj)
commandconcatenates a, *10^, and b
and the resulting string and obj are shipped off to the
doit( )
function,which loads the former into the latter.
Per the No offshoring needed subsection of the previous post, the
doit( )
action is actually unnecessary:an
obj.value = a + "*10^" + b
assignment works just as well.Starting a scope notes
If a is itself a positive integer power of 10, say 100000, then the while divisions will stop when a hits 10 and the output will be 10*10^4 versus the 1*10^5 output we would want: adjusting the while condition to
a >= 10
solves this problem.For as less than 10,
the while condition returns false from the get-go,
b stays at 0,
and the output has the form a*10^0,
which is what we would want
for positive as ranging from 1 up to but not including 10
and for negative as ranging from -1 down to but not including -10
but is not what we would want
for positive and negative as between 1 and -1
and for negative as less than or equal to -10.
We can accommodate all number as and also weed out nonnumber as with the following code:
var b = 0;
while (! isNaN(a)) {
if (a >= 10 || a <= -10) { a /= 10; b += 1; }
else if (a < 1 && a > 0 || a < 0 && a > -1) { a *= 10; b -= 1; }
else break; }
if (a == 0) { obj.value = 0; return; }
if (isNaN(a)) { window.alert("Please input a number."); obj.value = 0; return; }
obj.value = a + "*10^" + b;
For positive and negative as between 1 and -1, a is iteratively multiplied by 10 and b is decremented until a rises above 1 or falls below -1, e.g., 0.000017 (the acid dissociation constant for acetic acid) is converted to 1.7*10^-5.
When a reaches its final value, the
! isNaN(a)
condition is still true, so the loop is terminated with a break statement, otherwise it would run indefinitely.The a value can be 0 or the empty string
if the user respectively enters 0 into or leaves blank
and s the
prompt( )
box that pops up if either(a) the total field holds 0 or is blank initially
or (b) the user does not answer y to the
prompt( )
query.(The preceding images are Preview-enlarged screen shots that were originally taken when using Firefox.)
In these cases - given that
"" == 0
returns true1 - the else if (a == 0)
clause resets the total value to 0 and ends the scie( )
function via a return statement.FYI: 0 is a
special case [that] does not have a unique representation in scientific notation, i.e., 0 = 0 × 100 = 0 × 101 = ...
By nonnumber as I specifically mean any and all a strings for which
Number(a)
returns NaN. A nonnumber a value is converted accordingly to NaN for the original a > 10
while condition1, which in that case returns false as when NaN is one of the operands of any relational comparison (>, <, >=, <=), the result is always false, quoting Mozilla, and the output again has the form a*10^0. We have seen previously that nonnumber strings include not just alphabetic text like Hello World but also legitimate mathematical expressions like 123*(456+789), which should be
eval( )
ed with the key before being fed to the scie( )
function. As detailed above, my code flags nonnumber as and then pops up a Please input a number alert, resets the total value to 0, and returns.1
When comparing a string with a number, JavaScript will convert the string to a number when doing the comparison. An empty string converts to 0. A nonnumeric string converts to NaN[, which always causes a false return]- see the Comparing Different Types section of W3Schools' JavaScript Comparison and Logical Operators page.
The null thing
Up to this point I have negligently not said anything about what happens if the user cancels the various SC function prompts, and now is a good time to do so. Clicking the button on a
prompt( )
box returns the primitive value null (not "null" as a string). Number(null)
returns 0 and isNaN(null)
relatedly returns false, and the null value that is returned by canceling the SC functions' 'Enter a number to do X' prompts2 does behave like 0 for the mathematical operations that follow those prompts, e.g., Math.cos(null)
returns 1 and Math.log(null)
returns -Infinity.2A user usually first sees a
'Do you want to use the current number in the total text box to do X?' prompt,
whose cancelation leads to an 'Enter a number to do X' prompt -
see, e.g., this code given earlier.
For the
scie( )
function, then, canceling the "Enter a number to convert:"
prompt (vide supra) gives an a = nullwhose
a > 10
while test returns false and
that is outputted as null*10^0. It would be better to intercept that null as we did the empty string and other nonnumber as, yes?The a = null gets through the modified
! isNaN(a)
while gate but there is some strangeness in null vs. 0 comparisons in thatnull >= 0 and null <= 0 both return true but
null == 0 itself returns false.
Stack Overflow has a Why 'null >= 0 && null <= 0' but not 'null == 0'? page at which commenters Michael Liquori and/or Christian C. Salvadó link to relevant sections in the ECMAScript-262 Edition 5.1 specification -
specifically, 11.8.5 The Abstract Relational Comparison Algorithm (ARCA) and 11.9.3 The Abstract Equality Comparison Algorithm (AECA) -
that together with other sections in the specification provide detailed procedures for carrying out such comparisons. In brief, here's what happens:
(R) For the null >= 0 and null <= 0 relational comparisons, null is converted to +0 (yes, positive zero) via a
ToNumber(null)
operation (this also occurs for the null > 10 relational comparison). The mathematical value of +0 is simply 0 (see the eighth paragraph of this specification section), and the ARCA tests if the left-hand +0 → 0 is less than the right-hand 0 and returns false, which is subsequently adjusted to true for the >= operator and for the <= operator.(E) For the null == 0 equality comparison, the AECA leaves null alone and returns false - that's it.
Anyway, getting back to the interception of an
a = window.prompt("Enter a number to convert:", "");
-canceled null in the scie( )
function, it follows that an a == 0
test isn't going to do the trick. A simple solution is at hand, however; we can trap null (or the empty string or 0 while we're at it) by Number( )
izing a before comparing it to 0:if (Number(a) == 0) { obj.value = 0; return; }
An archival aside:
We first discussed the
prompt( )
method of the window object, and the → null return, in Blog Entry #11, which dates to my early blogging days and which I admit I find somewhat painful to read today. My choice of links for that entry provides a snapshot of the thrashing around I did documentation-wise prior to discovering Netscape's and the W3C's reference materials. Most but not all of those links had been dead for a while when I began writing the current post; I've recently gone to the trouble of repairing the dead ones, so you can go check out The Prompt( ) Method for yourself if you would like a pristine taste of my 'humble beginnings'. ☺More ECMAScript specification notes, in the name of completeness
Without getting into its grammar productions, the 9.3.1
ToNumber
Applied to the String Type section covers the "" == 0
and nonnumeric string → NaN situations that were addressed earlier:If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber
is NaN.
The MV [mathematical value] of StringNumericLiteral ::: [empty] is 0.
In actuality, a relational comparison with a NaN operand initially returns undefined, which is subsequently adjusted to false.
The ECMAScript-262 Edition 5.1 specification went live in June 2011; the current ECMAScript specification is located at
https://tc39.es/ecma262/.
In our next episode we'll deal with two more
scie( )
function issues:(1) Do you like the 2.023*10^3 output format? No? I don't either. Let's see if we can change it to 2.023×103, shall we?
(2) I ran 12345 through the
scie( )
function and got 1.2345000000000002*10^4. Huh? What's with all those trailing digits? We'll get this worked out.Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)