The XNS_Utility.js file defines several basic functions and values used and/or available for use with the XNS suite. The idea is to simplify certain basic operations of the suite.
The returnTrue
function unconditionally returns
true
. The returnFalse
function unconditionally
returns false
. The returnFalseIfNaN
function
returns true
if and only if this
is not an XNS
number. Typically, these functions are assigned directly as the
isNegative
method of an XNS constructor's prototype property.
var returnTrue = function() { return true } var returnFalse = function() { return false } var returnFalseIfNaN = function() { return (this.compareTo(0) < 2) // Numbers will always return -1, 0, or 1 for compareTo, so for numbers this returns true. // NaN is not less than 2, so for NaN this returns false. // It is inadvisable to use this function outside of the Number XNS type. }
This function returns true if the this
object is not
recognized as an XNS number. It also returns true
for any XNS
number constructed with the XNS_NaN()
function, or for any
number or string value which is not a number in JavaScript. Absent any of
these conditions, the function returns false
.
function isXNSNaN(arg) { var type = typeof arg switch (type) { case "number": case "string": return isNaN(arg) case "object": return ((typeof XNS_Types[arg.xnsType] != "boolean")||(XNS_Types[arg.xnsType] != true)) /* The first checks to see if that type has been registered. The second checks to see if that type is active. The third checks a specific property of the number which the script has set. There are three special xnsType reserved values: "+Infinity", "-Infinity", and "NaN". For the first two, XNS_Types = true. For the last, XNS_Types = false. */ break; default: } return true }
XNS provides the ability to retrieve a literal notation for an XNS number. To do so correctly, XNS must extend the current JavaScript implementation with a few methods for core JavaScript constructors.
Each of these functions (with the exception of Number
)
returns "new constructorName(value)"
.
String.prototype.toLiteralString = function() { var response = this.replace(/\\/g, "\\\\") response = response.replace(/\"/g, '\\"') response = response.replace(/\'/g, "\\'") return "'" + response + "'" } Array.prototype.toLiteralString = function() { var args = [] for (var property in this) { if (typeof this[property].toLiteralString == "function") { args[property] = this[property].toLiteralString() } else { args[property] = this[property] } } return "[" + args.join(",") + "]" } Date.prototype.toLiteralString = function() { return "new Date(" + this * 1 + ")" } Error.prototype.toLiteralString = function() { return "new Error('" + this.message.toLiteralString() + "')" } Number.prototype.toLiteralString = Number.prototype.toString
This is an array intended for storing an order of preference for XNS
number types. Currently, it stores true
and false
values, though these values I expect to replace with number values in the
near future.
var XNS_Types = [] XNS_Types["+Infinity"] = true XNS_Types["-Infinity"] = true XNS_Types["NaN"] = false
For the toMathML()
functions, we need a common variable
referencing the MathML namespace.
const xmlns_math = "http://www.w3.org/1998/Math/MathML"
One weakness of JavaScript in terms of conditional statements is the inability to succinctly declare a compound inequality such as "3 < x < 5". For JavaScript number types, this statement would typically be:
if ((3 < x) && (x < 5)) { /* statements */ }
But, using the compareTo()
methods as most XNS numbers will
require, it would actually be:
if (((3).compareTo(x) == -1) && (x.compareTo(5) == -1)) { /*
statements */ }
XNS provides a function to simplify this expression:
if (ineq(3, LT, x, LT, 5)) { /* statements */ }
There are eight unique top-level objects XNS_Utility.js creates:
const LT = {}, LTE = {}, EQ = {}, LGT = {}, GT = {}, GTE = {} const AND = {}, OR = {}
These indicate the following:
LT | The argument preceding LT must be less than the argument following LT. |
LTE | The argument preceding LTE must be less than or equal to the argument following LTE. |
EQ | The argument preceding EQ must be equal to the argument following EQ. |
LGT | The argument preceding LGT must be less than or greater than the argument following LGT. |
GT | The argument preceding GT must be greater than the argument following GT. |
GTE | The argument preceding GTE must be greater than or equal to the argument following GTE. |
AND | Both the conditions immediately preceding AND and the conditions immediately following AND must be true. |
OR | Either the conditions immediately preceding OR or the conditions immediately following OR must be true. |
The ineq()
function requires an odd number of arguments, at
least 3. Each even argument must be one of these eight constant values, and
each odd argument must be a variable or XNS number you wish to compare.
function ineq(num0, comp0, num1) { var in_flag = 1 /* in_flag == 2: unconditionally true in_flag == 1: true so far, unconfirmed in_flag == 0: false so far, unconfirmed in_flag == -1: unconditionally false */ var in_loop = 0 var left = null, right = null, op = null, result = null for (in_loop = 1; (in_loop < arguments.length)&&(in_flag < 2)&&(in_flag > -1); in_loop+=2) { left = arguments[in_loop - 1] right = arguments[in_loop + 1] op = arguments[in_loop] result = left.compareTo(right) switch (true) { /* The goal of each loop through is to find a condition which returns false. In this situation, we can set the in_flag to 0. An OR condition means we can add one to in_flag. An AND condition means that if it is currently false, we must end our search. Because NaN does not compare well to other numbers, I explicitly must state conditions which would pass LTE, LGT and GTE, and then negate those results. */ case ((op == LT)&&(result != -1)): case ((op == LTE)&&( !((result == 0)||(result == -1)) )): case ((op == EQ)&&(result != 0)): case ((op == LGT)&&( !((result == -1)||(result == 1)) )): case ((op == GT)&&(result != 1)): case ((op == GTE)&&( !((result == 0)||(result == 1)) )): in_flag = 0 break; case (op == OR): in_flag++ break; case (op == AND): if (in_flag < 1) { in_flag = -1 } break; default: } } var response = false if (in_flag > 0) { response = true } return response }