list of numbers
From Wiki
This article or section is in the middle of an expansion or major restructuring. You are welcome to assist in its construction by editing it as well. If this article has not been edited in several days, please remove this template. This page was last edited by Holy (talk| contribs) ago. (Purge) |
Numbers are a means to add some programmatic functionality to Sword of Moonlight via calculator like mathematical expressions. Numbers are typically setup inside of an Ex.ini file. This list contains built in and so-called system numbers only.
Preface |
---|
This page is not and should not be a definitive document describing the programming language and environment represented here. Yet still as with any programming methodology familiar words take on new and peculiar meanings. So here, in what would otherwise be a big empty space to the side of the Table of Contents, is a hopeful attempt to develop a formal nomenclature that over time will hopefully be of use to students and wiki editors alike.
But first, background. This technology was originally and still is developed as a method to input mathematical expressions or formulas into configuration files that would otherwise only be able to receive fixed numerical values. Its audience is the lay public, non-programmers, or more specifically anyone who ever came to rely upon a calculator to pass their high school math exams. It never was a programming language per se. In fact it was designed very consciously to restrict the realm of possibilities available to its would be programmers. Still basic calculator style mathematical notation shares enough in common with basic full featured programming languages to present with it most if not all of programmings core challenges and complexities. As not really being a proper programming language, there never actually was a proper name, much less a short and catchy one. Retrospectively the most historical name has to be Excalculator. It is after all encapsulated within the EX::Calculator C++ class, as part of the Ex framework, engineered to add programming features to the Ex.ini configuration files, to be featured most prominently by the Excellector graphical configurator, sure to include a popup calculator tool destined to be titled Excalculator and or possibly additional names as a stand alone calculator application part of the Sword of Moonlight software suite. Speaking of nomenclature. There are two fundamental building blocks to keep in mind. They can be easy to remember, because they appear very similar side by side. One we call "Sums" and the the others are "Sets". Each are described methodically in detail below: A Sum (singular; sounds like SOM) is a slot, or what is called an item within the language machinery's source code, within a Number, capital N, known as a table by the source code, that is indexed by a Subscript, and represents both sides of an equation, where the side to the left of the equal sign (we don't solve algebraic equations) is indicated by its Number and Subscript, and the side to the right of the equal sign is a mathematical expression, which can include input parameters, what programmers would call arguments, in order to express a mathematical function. A Set is a more advanced feature (in fact it is yet to be adopted or implemented) that is analogous to a Sum. In fact sets share the namespace with sums, so that a set is assigned to a sum. A Set is a set of Sums and or other Sets and or nothing. Technically a Set is a multiset of links, or what programmers call references, to sums and by extension other sets. Because sets can contain within them even more sets, sets can be arranged into tree like structures, and have been designed to facilitate many common patterns familiar to programming languages of all stripes. Still even with sets "Excalculator" like a calculator takes a strictly "write-only" approach that can (probably) safely be classified as a "purely function programming language". Of course just like a calculator, its memory is configurable and its calculations are always at the service of external applications. More specifically Excalculator's job is to spit out numbers, little n this time. We also say numbers to refer to intermediate values. Where Numbers refer to names, or what programmers would call identifiers, or an algebra text book might refer to as "variables". Just for the record we don't say variable to refer to named numbers. We take the programming convention of referring to figures as being either variable or constant. A constant figure does not change for any reason ever. Whereas a variable may change, could change, for all we know will change, and probably just changed. In other words, a variable is an unknown. This can have implications. Not limited to optimizations, wherein many constants values are collapsed into a single value. If an expression contains a variable, then that part of the expression will prevent a complete collapse. You'll have to settle at the very least for a variable part, and a constant part, or just the variable part if it is a pure variable or the constant part happens to collapse to a 0 additive term. |
Sword of Moonlight
Variables
c
pc
npc
Constants
Legend | |
---|---|
SOM_SYS | settings part of SOM_SYS (SOM_SYS.exe) usually kept in the Sys.dat file. |
m/s | the constants units are meters per second. |
c/s | the constants units are radians per second. Note that constants based on figures originally in degrees are converted to radians. |
- _WALK (SOM_SYS; m/s)
- the player character walking speed.
- _DASH (SOM_SYS; m/s)
- the player character dashing speed.
- _TURN (SOM_SYS; c/s)
- the player character turning speed.
Serialization
It is possible to write a series of numbers. Care must be taken to not do so accidentally. The following table demonstrates the rules that must be observed. However the basic rules are pretty simple. If a mathematical operator has a space on one side, then it must have a space on its other side, and vice versa. In other words, 1 + 2 or 1+2. If a positive (+) or negative (-) sign appears in front of a number it must be flush with the number, or -1, not - 1.
input | produces | output |
---|---|---|
1 2 | => | 1, 2 |
2 +3 | => | 2, 3 |
3 + 4 | => | 3+4 |
4 + -5 | => | 4-5 |
input | produces | output |
---|---|---|
5 +-6 | => | 5, -6 |
-6+7 | => | -6+7 |
-7--8 | => | -7+8 |
-8 --9 | => | -8, 9 |
If you experience different results then that is a software bug that should not be relied upon in order to ensure you expressions continue to work correctly in the future.
Tip: where there is no empty space an expression cannot be interpreted as a series. 2(X) is 2*X, (X)(Y) is X*Y, and Y(2)X is X[Y(2)] and 2XY is XY[2]. This all works because plain numbers when written as a function behave as if multiplied. The rest is explained by #subscripts.
Space and separators
Spacing characters include space ( ), tab, carriage-return, new-line, and any other character that produces empty space wherever it appears. Note that tab and other kinds of characters sometimes appear as zero width spaces. This can be a nuisance as they will nonetheless be interpreted as space.
End of the line characters (carriage-return and new-line) are ignored along with any spacing characters that follow. When working with multiple lines care must be taken to observe spacing rules precisely. When a series is spread over multiple lines an explicit separator (#,;) should be placed between the last element on the line and the first element on the next line. A semicolon (;) at the end of the line is recommended for this.
Like with HTML (except for following the end of a line where empty space is ignored) one space, or two spaces, or any number of spacing characters (and or separators) is collapsed into a single space for purposes of serialization.
,;
The colon (,) and semicolon (;) are reserved separators. They are strictly equivalent to a space ( ) character, except you can see them as written. In other words 1 2 or 1,2 or 1;2 it doesn't matter. If necessary more separators can be added or an extension can be provided to allow for the definition of custom separators.
Note that separators are simply filtered out. So if you write 1,+,2 this is equivalent to 1+2. Care should still be taken to observe the rules of serialization and cautions about working with multiple lines in the previous section.
%
A percent sign (%) can appear as the first symbol in an assignment or after a separator in or order to suppress default parameter resolution. Graphically the slash means no as in "no smoking" and the two circles represent the original parameter and its default parameter. So altogether % can be read: "no two parameters". Of course, everything defaults to #nan. Refer to #_.
Tip: It's a good practice to highlight all default parameters in this way. Even when parameters are not present.
Subscripts and labels
A named number can be written with a subscript. When not so, the subscript is 0. Subscripts must be positive whole numbers no more than 65534. In reality each number is a 1D table of numbers, or numerical values, each distinguished by its subscript. Built in numbers (including functions and operators) almost always make use of only the 0 subscript.
Built in mathematical operators like + (plus) are the same, except with the further limitation that (because of #placeholders) it is not even possible to refer to them with subscripts. That said, were it possible to overwrite them, internally (from within their own assignments) they can refer to their own subscripts. Refer to #_ #_S and #_$.
In other words, the number itself has no value, but rather its subscripts do. The value of a number without an expressed subscript is the value of its first (0) subscript. Without introducing extended Unicode characters a subscript can be written in the following ways:
notation | interpretation |
---|---|
A[0] | 0th subscript of A |
B | 0th subscript of B |
C[1] | 1st subscript of C |
1D | 1st subscript of D |
E[1][1] | 2nd subscript of E |
F[1+1] | 2nd subscript of F |
notation | interpretation |
---|---|
1G[2] | 3rd subscript of G |
f(X)H | "f of Xth" subscript of H |
f(X)I[+1] | "f of X plus 1th" subscript of I |
f(X)1J | incompatible (#nan) |
K[-1] | not allowed (nan) |
L[2][-1] | still not allowed |
[]
Square brackets ([]) surround labels and are another way to write subscripts. Square brackets always appear directly adjacent to the right side of a named number. Labels can only be written inside of square brackets flush to the brackets on both ends.
There is however a special named number with a "zero character" name. In other words, where there is 2*[1] between the * and the [ there is actually a number there. This number is temporary within the scope of an assignment and behaves differently from other numbers. When its subscript is a plain positive whole number flush to both brackets. For example [1]. It is said to be a placeholder. If the subscript is not a placeholder then it is a label. Each such label counting left brackets ([) from left to right increases the number of subscripts by 1 and the content of each label is substituted for the corresponding placeholders. In addition the label itself is replaced with a placeholder such that [X*Y]+[0] becomes X*Y+X*Y.
Subscripts (inside of square brackets or otherwise) cannot be less than zero (0) or negative. Fractional numbers are rounded down to the nearest integer. Sets of brackets can be chained together—in addition to a subscript written without brackets to the front of its number—so that each successive subscript is added to the sum of previous subscripts in the chain, so that X[1][+2] becomes X[3]. Labels are not required to be unique. When combining subscripts, label resolution (the search for the label) begins at the previously indicated subscript, or 0 if a label appears as the first subscript.
A label must be able to be converted into a constant subscript. This is by design. Labels in other words are merely a more literate way to write a literal subscript. A subscript is "constant", or invariable, if under no circumstances does it ever change. A function's local input parameters are always assumed to be inconstant, or variable, but this only holds true within the function itself. From outside the function, the parameters have definite values, and therefore the result, or yield, of the function is constant insofar as its internal parameters are also constant. In other words, even if it just so happens that a parameter of a function is only ever one value, that value is still held to be inconstant. Variables include #r and #Variables.
Note: many labels can be applied to the same subscript. It is not possible to remove a label once applied. Many subscripts with the same label can coexist by way of offset based label resolution described above. However brackets will be interpreted as a label whether the label appears before or after the indicated offset. Whether this behavior should be considered a defect or feature has not been decided; regardless this behavior is extremely unlikely to ever change.
Mathematics
With math it is possible to write a number as a mathematical expression with 0 or more input parameters. Refer to #_.
Calculations
A basic expression should appear familiar to everyone who has ever relied on a calculator to make it through a grade school math course. In fact it is never necessary to deviate from standard calculator notation. What follows is a refresher course along with an introduction to some quirkier ways to write expressions that can either be enlightening or treacherous, depending on how you look at it.
Grouping semantics allow expressions to contain subexpressions. Series within a subexpression are interpreted as input parameters. Refer to #() and #||.
An expression is made up of numerical terms held together by mathematical operators. A term can be a single number or a group of numbers. Operators resemble punctuation. For example: 1+2 includes two terms, 1 and 2, and one operator, +, or plus.
This distinction is stressed because each expression is a kind of computer program where each character in the program must be strictly interpreted. There is no tolerance for error, and in 9 out of 10 cases no red flags to be raised in case of error. Intolerance is a feature of all programming languages, and is nonnegotiable. Red flags on the other hand, can be supplied on demand (at the cost of alternative ways to write expressions.)
Numbers directly adjacent to (but not inside of) parentheses become a function of the inner terms of the parentheses, or the function's input parameters. Plain numbers, such as 1, 1.5, or (1.5) share a built in function: multiplication: however in keeping with arithmetic the priority, or precedence, assigned to this function is equivalent to regular multiplication (in other words it is as if an invisible #* is situated between the numbers.) Other numbers can only be written with the parentheses on their right. Refer to #() (when written on the left the result is a #subscript; not a function at all.)
While operators technically are functions, they are not usually written as such. However it is possible to do so. For example, 1+(2,3) adds together 1 2 and 3.
Wherever a term should logically appear but is omitted a 0 is provided. For instance. Operators always have a left term and a right term. And groups are not allowed to be empty. Consider -1+2. Which becomes (0-1)+2. Note that it does not become 0-1+2. The distinction can sometimes make a difference. Though less common, the same rule applies on the right: 1- becomes 1-0. Here parentheses are not needed. And last but not least: () becomes 0 (so consider that f() becomes f(0) where f is some mathematical function.)
Likewise terms and operators must always appear together. If an operator is omitted then a + is provided. So (1,2) becomes 0+(1,2) adding together 0 1 and 2 (and 1 becomes 0+1. Rules are rules.)
Arithmetic
Basic arithmetic includes the + - * and / operators used for addition, subtraction, multiplication, and division respectively. The operations are carried out from left to right, except that * and / have a higher what-is-called precedence, and are therefore always carried out first (barring grouping. Refer to #().)
these | equal | this |
---|---|---|
1+2 | = | 3 |
2-3 | = | -1 |
3*4 | = | 12 |
4/5 | = | 0.8 |
these | equal | this |
---|---|---|
1+2*3 | = | 7 |
(1+2)*3 | = | 9 |
3/0 | = | #inf |
0/0 | = | #nan |
When written with input parameters these operators can operate over more than two values. For example, (1,2)+(3,4,5) equals the sum of 1+2+3+4+5. The same is true for * - and / (for example (1,2)*(3,4,5) equals 1*2*3*4*5.)
Tip: note that +(3,4,5) equals 0+3+4+5. This is inconsequential, however *(3,4,5) may produce unexpected results since 0*3*4*5 is 0. As is *3 (on the other hand. Consider *[+1][+2][+3]+<your actual expression with #placeholders here>. Here we have three internal parameters front loaded with nearly unmistakable intent.)
()
||
Enclosing an expression within two vertical bars (|) yields its absolute value. For example, |-7| makes 7. But you must beware that nesting without parentheses (#()) is not supported. Something like |c[|A|]| also works where square brackets are able to be used in place of parentheses.
In other words: |(|A|-|B|)| does work. While ||A|-|B|| does not work. Alternatively consider #abs(|A|-|B|).
abs
Decision trees
?:
if
Logical operations
_E
and
nand
or
nor
xor
xnor
Complex numbers
x
y
iy
Identity coalescence and inequality
nan
inf
not
neg
Reflection and recursion
_
_ is a variable that changes from assignment to assignment. The 1st subscript (1) is the first of the current input parameters into a function. The 2nd subscript (2) is the second parameter. And so on. The 0th subscript (0) would be the function in question. It is always equal to #nan (because a "stateless" function with equivalent input parameters will always be equal to itself. It can reliably be used as an ever present shorthand for nan.) Refer to #_S.
The sums immediately above a function fill out its input parameters where there are fewer than expected available. In other words, these sums function as default parameters. Each default parameter has the available parameters forwarded to it, one by one in turn, so that each adds its default value to the growing list of available input parameters.
Parameters of variable subscripts do not warrant the inclusion of defaults, however if defaults are elsewhere included, the defaults values are used. In other words _[#r[2]] will not trigger the default evaluation of _[1] however *_1+_[r[2]] is a trick that works as a workaround since *_1 is 0. Alternatively *_4 will yield defaults for _1 _2 _3 and _4. There is an extension based limit placed on default parameters. An extension and default is forthcoming.
Labels applied to defaults are mapped to _ to enhance readability. The mapping begins at the first default. Defaults are not well suited as ordinary functions, yet still they play by the same rules. It is therefore best practice to avoid labeling the forwarded input parameters of defaults and furthermore to never use a default expressly. Or to put it another way: only use defaults as defaults.
Tip: consider #n(_[1]) to count a function's local non-default input parameters.
_S
_S is a shorthand way to refer to numbers in a series within a serial assignment. So _S[0] is the first subscript in the series, _S[1] the second, and so on. Note that _S refers to subscripts only and therefore does not apply to values within a sub-expression, for instance X = (1,2,_S[0]) becomes X = (1,2,(1,2,(1,2... or an infinite recursion resulting in undefined error behavior. Whereas X = 1, 2, _S[0] becomes X = 1, 2, 1 where X[0] is assigned 1, X[1] 2, and X[2] 1.
The subscript component of _S must be a single plain number. This is limited to 0_S or _S[0] where 0 is any positive whole number. Within sub-expressions consider using #placeholders instead.
_$
_$ works just like _S except it refers to the previous assignment of the subscript while it is being assigned. So if X is 2 (or an unknown value) and you want to double X, it is possible to write X = 2*_$. Where X = 2*X would be X = 2*(2*(2*(2*(2*... or an infinite recursion resulting in undefined error behavior.
In addition to the subscripting restrictions imposed upon #_S a subscript of _$ can only appear within the same subscript that is being assigned to. So that X = 1, _$[0], 2 is an error. Whereas X = _$[0], 1, 2 is not.
_N
_N is undefined. _N(X) yields the subscript of X, or 0. _N(X[2]) yields 2. _N is provided if for no other reason so that you can subtract from the subscript of a label like so: X[_N(X[label])-1] whereas X[label][-1] will not work because subscripts must be positive or not less than zero. _N complements #n.
Statistical analysis
n
Despite appearances, n is a special function. Its input is a single named number with subscript. It yields the #sums count starting at the subscript. So if #c holds 1024 sums, then n(c) yields 1024, and n(c[1]) yields 1023. Furthermore n(c[1024]) yields 0, and n(c[1025]) yields #nan.
n works with input parameters as well. If #_ is the input parameters of a function, then n(_[1]) yields the number of input parameters. Default parameters do not count. n complements _N.
int
int(A) yields the whole number part of the mixed fraction A. For complex numbers int(A) is equivalent to int(x(A))+int(iy(A)).
mod
mod(A) yields the fractional part of the mixed fraction A. For complex numbers mod(A) is equivalent to mod(x(A))+mod(iy(A)).
Note: a mod or modulo function often accepts two input parameters yielding the remainder of the inputs. This mod simply complements #int. Calculating the remainder of A and B is as simple as mod(A/B). Whereas mod(A,B) will simply yield mod(A).
min
max
r
Despite appearances, r is not a function at all, but a pseudo number containing random numbers. r[2] is a random number between 0 and 1. r[1] is 0. Subscripts cannot be larger than 65534. A larger subscript yields #nan. r[0] is an unconstrained positive whole number. The default random number generator for r without input parameters is the C programming language's rand function. This function never actually produces numbers larger than 32767. There's no such thing as a random number. Most functions demonstrate obvious biases. Input parameters are ignored by all current versions of r.
Note: r never contains the same number unless by coincidence. To make use of a random number that does not change consider using an in-game event to record a random number into one of Sword of Moonlight's counters. Refer to #c.
Transcendental functions
^
cos
exp
log
pow
sin
Sets
Sets are a proposed feature. Implementation (and finalization) is to be delayed until thought necessary.
Proposal
A set here is not a set of number values. It is a multiset of named number and subscript pair references referred to as elements below. If a plain number is added to a set it is said to be anonymous. The individual numbers of a set are accessed by ordinal with #el.
Sets and #subscripts are incompatible. In other words, el(A,1)[2] does not work (where el(A[2],1) does—just to be 100% clear—but means something completely different beside the point. Bottom line, subscripts are for numbers. Also note that el(A,1)[2] does not produce an error as [2] is interpreted as a #placeholder.)
Where a set is operated upon like a number it is equivalent to its 0 ordinal element. And if that element is itself a set, the 0 ordinal element of that set. And so on.
Tip: a named set B equal to {A} becomes the functional equivalent of A. Although references to A remain distinct from references to B (consider #no(C,{A}) where C contains references to B but not A. Note that neither does this extend to subscripts. Therefore B[2] is not by extension functionally equivalent to A[2].)
Elements default to a single element set containing #nan. It is explained below that this can be written {nan}. Note that nan is not a value. But yields the value NaN when expressed without input parameters.
{:}
An empty set is written as {}. A two element set is written as {A,B} or {A B}. Here A is assigned ordinal 0, and B is assigned ordinal 1. Ordinals can be skipped by writing {A,2:B}. Here A is again assigned ordinal 0, and B is instead assigned ordinal 2. Ordinals must be positive whole numbers.
If A is itself a set then this must be acknowledged by writing {A} or {{A},B} or else A will be taken as the 0 ordinal element of set A. This does not introduce an intermediary set. Too add an anonymous set write {{A,1,2},B} or {{{A},1,2},B} depending on whether element A is to be a set or number reference.
el
el yields undefined behavior. el(A) yields A as a set, or {A}. el(A,1) yields the ordinal 1 element of the set A as a set. el(A,1,2) yields the ordinal 2 element of the ordinal 1 set of set A.
no
no yields undefined behavior. no(A) yields one more than the greatest ordinal of set A, or 0 if A is the empty set {}, or 1 if A is in fact not a set.
no(A,1) yields the number of elements equal to the number 1 with respect to #_E. no(A,1,2) yields the number of elements between the range of 1 and 2. no(A,1,2,0) yields the number of elements between 1 and 2 with a precision of 0, or 0 is used in place of _E.
no(A,{B}) yields the number of elements of set A that reference B. no(A,{B,C}) is equivalent to no(A,{B})+no(A,{C}).
Tip: no(A)-no(A,nan) yields the number of non-NaN elements in set A. But this looks for the value NaN. Since ordinals default to {nan} you may want to look for no(A,{nan}) instead.