![]() |
![]() |
![]() |
Numeric Solver Fractals and Turtle Graphics |
Fenestra - |
JavaScript - |
Introduction:
Sxript is a high-level, interpreted, functional/procedural general-use programming language designed for numerical evaluation and problem solving with vectors, matrices, calculus, linear algebra, differential equations, and complex data types. The Sxript language utilizes variable storage, recursive functions, sub-programs with private scope, high-order functions, lambda calculus, plus other elements such as file IO and graphical output. The mathematics subsystem, formerly known as the STxAxTIC Math Library, is designed for arbitrary-precision calculations. Sxript may be used as a stand-alone tool, or one may #include the Sxript apparatus as part of another program. Prototyped in a BASIC dialect, the main codebase is QB45 compatible; designed for use with modern QB64 and FreeBasic compilers. Implementations in C-family languages, namely C++ and JavaScript, are a near one-to-one translation of the prototype codebase. Sxript is a Rosetta Stone in this sense, expressing the same instructions in several languages independently. |
Download
The following compressed file contains the entire Sxript project, including this web page. Sxript.zip Legal Sxript is conveyed as open source free software, as defined on gnu.org. License included with download. Contact wfbarnes@physics.umass.edu |
![]() |
Build Notes
|
Terminal Interface (return to contents) |
Hello World
Find and run the executable named Sxript. (By default, the executable ships in the Sxript root folder, but it's always best if you compile on your own system.) Your console should take on an appearance resembling the text box below:
When Sxript takes over the console, you get the ASCII logo, followed by a brief welcome message and version information. Waiting for input at the bottom is the Sxript command prompt. To actually print "Hello World" on screen, try replicating the following session:
|
Hello Math
The mathematics subsystem underlying Sxript goes to arbitrary precision, defaulting at DOUBLE precision (rougly 16 significant digits). A "Hello Math" test run is shown in the text box below. With the numerical precision set to 33, the first command sent to the library is to evaluate 2/3, and the result, as expected, is +0.666666 (without writing the rest of the 6's). Next we send the command 4/3, giving +1.333333. So far, so good.
|
Accuracy Factor
The global constant that dictates the precision of numerical output can be adjusted on-the-fly with with operator acc(x), where x is the number of numerical characters retained in a number. For a high-precision test, we first choose a high number, for instance, 398. Next we input a problem that will surely occupy all 398 digits, such as a repeating decimal. Choosing the square root of 2 for an example, we type sqr(2). The result is precisely 5 lines long, as the console is 80 characters wide. (The sign and the decimal take up the two extra spaces.) |
Order of Operations
The "order of operations" obeyed by Sxript matches the standards of science and mathematics. (We will not imitate the erroneous behavior of certain systems such as spreadsheet programs.) Specifically, structures in parentheses are interpreted first, and in the order from "most embedded" to "least embedded". Next, any calculations involving the exponent ( ^ ) operator are interpreted into pow_( ) functions. As expected, all multiplication and division operations are performed, followed by addition and subtraction. Finally, the logical AND and OR operators, & and |, respectvely, are evaluated. |
Variable Types (return to contents) |
Real Numbers
In Sxript, there is only one type of real number - there is no distinction between single precision, double precision, floating point, long, etc. We have one number type here with arbitrary* decimal precision (* some operations return double precision only). Read more about the numerical accuracy factor above. All numbers are formatted with precisely one sign and one decimal point. For numbers outside the neighborhood of zero, scientific notation is used. Numeric literals can be expressed simply by writing a number. The format of the number need not be strict at the user input level, meaning cos(3) is just as good as cos(+3.0). When a correctly-formatted numeric literal is sent to the interpreter, the number slips through with no new changes, signaling that evaluation is finished. The num(a,y) operator is used for storing a number. The letter a is set to hold whatever y might stand for, so long as it boils down to a real number. Representing a number by its name is done with the "pound" operator #( ). For instance, to multiply a by +3.0, one would type #(a)*3 or, equivalently, 3*#(a). |
String Variables
Strings, like numbers, can be stored, manipulated, and be processed through functions. Strings literals should be wrapped between the "un-shifted tilde" ( ` ) symbol and the the "single quote" ( ' ) symbol, and when the interpreter detects a raw string as input, it slips through untouched. (In fact, comments in the Sxript language are led by this same symbol.) A string variable is stored by using the string(a,`y') operator, where a is the name of the string, and y is the contents of the string. Note that an unwrapped string will still pass through this function, but any blank spaces are closed. A string is represented through its variable name by the "string" operator $( ), which takes a string name as an argument. The sole job of $( ) is to swap the string name for its literal representation. |
Vectors and Lists
The term "vector" shall be synonymous with the term "list", which is defined as a collection of items (numbers or strings, other vectors, whole matrics, and so on). Each item (or argument or element) is separated by the semicolon ( ; ) symbol, and the whole vector is contained in sharp brackets, ( < > ). The number of items or elements in the vector/list is called its dimension. Vectors of equal dimension can be added, in where elements of similar index combine to make a new vector of the same dimension. Vectors can also be "stacked", which appends one vector at the end of another, resulting in a vew vector of combined dimension. A vector can contain another vector, or even a whole matrix in any element. A vector can be created and/or stored by the vect(a,y) operator, where a is the name of the vector, and y is the representation of the vector. A vector can be represented literally, for example <1;2;3;4>, or symbolically by the v( ) operator, which takes a vector name as an argument. The sole job of v( ) is to swap the vector name for its literal representation. Vectors are, generally speaking, something I call "weakly evaluated". For instance, the vadd(a,b) merely inserts a plus ( + ) symbol between the respective elements. The resultant vector is not evaluated. To finish the job, use the veval( ) operator. |
Matrix Nomenclature
A matrix looks like a block of numbers. More specifically, each row a matrix constistutes a row vector, and each each column makes a colummn vector. The dimensions of a matrix are specified by two numbers, denoted rows (counting down) and columns counting across. For instance, a square matrix with three entries on a side will have dimension (3,3). Add an extra row to the matrix, and the size becomes (4,3). Two matrices can be added if they are of equal dimension, or multiplied when their dimensions obey (n,m)x(m,p), resulting in a matrix of dimension (n,p). There are no such things as matrix subtraction or division. A matrix, much like a function, can "operate" on a vector, transforming the vector into a new one. In this case, the number of colums in the matrix must match the number of rows of the vector. The rows (vectors) of a matrix are separated by the vertical slash symbol "|" ( shift + \ ), and the entire matrix is contained in "square" brackets [ ]. |
Operator Overloading (return to contents) |
The mathematics operators + , - , * , / need not be limited to numerical evaluation. The following chart lists all cases where operators are meaningful. |
|
(number) |
(string) |
(vector) |
(matrix) |
||||||||||||||
|
|
|
||||||||||||||||
|
|
|
||||||||||||||||
|
|
|
||||||||||||||||
|
|
Writing Programs (return to contents) |
Hello Text File
Commands need not be sent to the interpreter one by one. To execute a list of commands, save them to a text file. Three easy steps...
|
Good Sxripting Practice
|
Storing Numbers
The operator num(foo,num) stores the number num in the variable foo. Thus, on line 3 in (hello.txt, the sample from Step 1), the operator num(a,5*5) stores the value +25.0. The number stored in a is called by typing #(a), as seen on line 4. The output of that particular line must be +25.0-8.0=+17.0, stored in the variable #(b). |
Loop...Next Structures
The loop...next structure is a method for executing a chunk of code in repetition. The loop statement causes all statements before the corresponding next statement to be executed an integer number of times, a set by the value immedietely preceeding the loop keyword. For example, the following code boxes do the same thing, namely, repeat ( ... ) 15 times:
|
Anchor and Goto
The Sxript language does not support line numbers (although you are free to write numbers on their own - they will simply be formatted and not printed unless told to do so). If a particlar line in the code must be jumped to, insert the operator anchor_foo, where the anchor is named foo for this example. Returning control to foo is accomplished with goto_foo. for instance, consider the following script:
The output consists of the numbers +2.0, +4.0, and +10.0. The calculations 3+3 and 4+4 were never performed. |
if ( =1 )@(goto)
The if...goto structure is a mechanism for passing control to an anchor. (An anchor must be defined in order to use IF). A typical IF statement might look like:
Supposing there is an anchor named done, control is passed to that anchor if the quantity between _ and @ equals +1.0. If the quantity enclosed between _@ is anything other than unity, control is passed to the next line, and not to done. The function used in this example, kron({x},{y}), happens to return +1.0 if the arguments match, and +0.0 if they don't. In BASIC dialect, the above line literally reads "IF Y=X THEN GOTO done". To see if structures in action, following are two slightly different programs, with the output of each stated at the end.
|
Sub-Programs (return to contents) |
The run( ) Operator
A sequence of commands can be condesed to one line and passed to the run( ) operator, completely bypassing the file-IO aspect of sub-programs. Inside the parenthesis, lines are separated by the colon ( : ) symbol. A relatively simple (but not overly trivial) one-line script is:
In the above, we first set a variable a to contain zero. Next, we blurt out the number 5, which tells the following loop statement how many times to iterate. Inside the loop, we add 1 to the number a, and store the new value in a again. After five iterations, control passes the next statement. The final (and at this point, necessary) step is to print the contents of a. For another example, consider the code box below, which is a slight modification of the previous case. The new version adds the integers from 0 to 5. A second variable b keeps track of the present loop iteration. The output of this particular routine is +15.0:
The print_ keyword has a special role within run( ). In short, print_ may be regarded as the "return" keyword in C-family languages. Regardless of what happens inside run( ), the only visible output is that which is led by a print_ statement. If there are multuple instances of print_ inside a sub-program, the output emerges as a string:
|
Sub-Program Scope
The Sxript language supports local and global varibles. When control passes to the inside of a run( ) structure (or to a text file program), all previously-defined variables are available to read, and also temporarily rewrite. There is no need to pass arguments to a sub-program. When control exits the run( ) structure (or text program), all numbers and strings restore to their previous values. Only the information passed by print_ escapes the run( ) structure. Two keywords have been designated to control the scope of a variable: global( ) and local( ). All variables default to local. When explicitly set to global, a variable "survives" the reset process when leaving a sub-program. The following program (output included) demonstrates the concept:
|
Functional Programming
(return to contents) |
Defining Functions
Functions are created with the func[ ]= keyword, where the square brackets hold the function name, and the content goes on the right side of the equal sign. The arguments that are passed to a function need not be counted or specified. Arguments are simply "used" in the definition, strictly formatted as {x}, {y}, and {z}. The symbols {x}, etc. can represent any variable type, and are not limited to real numbers. For instance, to pass many numbers to a single function, let {x} be a vector containing them. To illustrate defining functions, the following code box contains function definitions of one and two arguments, respectively.
Functions are called by their name, followed (with no spaces) by the required arguments, as in:
Functions can be nested inside other functions, and may also be nested within themselves:
If a function's definition is not readily visible, the keyword func?, followed by the function name, will return the contents of the function as a string, as in:
|
Functions as Variables
In the text box below, the function cow does not multiply variable x by variable y. Instead, the symbol {x} is supposed to be a function name, and {y} is its argument (which may itself be another function). For example(s), the square root of 17, and then the tangent of 13, can both be evaluated using cow as follows:
Notice that the function cow was the actual "function" called in this case. Strange as it might seem to the newbie, the function names "sqr" and "tan" were sent as arguments, as if they were ordinary variables. |
Nesting Sub-Programs in Functions
A run( ) statement can be contained in a function. For instance, the function sumints takes a number {x}, and sums the integers from zero to {x}.
For a more juicy example, following are two functions for computing the factorial (of an integer). The first method uses the loop...next structure, and the second uses if...goto structure.
|
Highly Nested Functions
Let us generalize the definition cow={x}({y}) from the example above by defining:
The new function bull takes three arguments. The first argument, {x} specifies a function by name only. Next, {y} is the argument that can be passed to {x}. Finally, {z} is the number of times to apply {x}({y}). The following examples apply the functions cos({x}) and sin({x}), respectively, 14 times each. The computations are done in two different ways (output suppressed).
|
Anonymous Functions
An "anonymous" function is a function without a name, "defined" and used in-line with its argument(s) all at once. Fundamentally, anonymous functions are a convenience and not an essential construct. In Sxript, an anonymous function is created with the keyword lambda(` '). The idea is to place lambda(` ') where you'd ordinarily place the name of a function. The actual task carried out by the function is enlosed between the unshifted "tilde" ( ` ) and the apostrophe ( ' ). The following code box demonstrates a few uses of lambda(` ').
|
Compounding Functions
A demonstration of high-order functions.
|
Haskell Imitation
The content for this example comes from a rather entertaining 10-minute video on Haskell: Why Haskell is Great ![]()
|
Object-Based Programming
(return to contents) |
JavaScript Imitation
Being a `classless' language, JavaScript achieves object-oriented programming by exploiting functions, with Sxript proceeding in this spirit as well. The following example was taken from a tutorial on OOP: Intro to (JavaScript) Object-Based Programming
|
OOP Demo 81
It took many dozens of incremental changes to get this `right'. The number 81 gives some indication of the effort made.
|
2D Plotting in SCREEN 12
(return to contents) |
Any Sxript-enabled program written in QB64, FreeBASIC, or QB45 that runs in SCREEN 12 can plot functions of the form y=f(x), producing output resembling that made by a graphing calculator. In the host language statement EvalInput("",STxAxTICAccuracyFactor), we specify the function to plot, the horizontal range, and the step resolution, respectively as follows:
When executed, an image resembling the screenshot below will appear. ![]() Screenshot: A Sxript-enabled QB64 program showing a 2D Plot. The plot runs from x=4 to x=8 with a resolution dx=0.025. The red-tinted numbers in the plot window corners denote the minimum/maximum x/y values, respecively, reached by the plot. They do not label the corners necessarily. |
ASCII Plotting
(return to contents) |
Plotting functions is not limited to SCREEN 12. In the spirit of generating a kind of "universal" output, a simple ASCII plotting feature has been implemented. In any text interface, enter the command:
The last argument in plotascii specifies the destination of the plot. For a text stream to the terminal window, use the @ symbol (as shown). If running the MathBlab chatbot, replace @ with the name of an an IRC user or channel, as in #qb64. |
3D Plotting (return to contents) |
If any text file consists solely of three-dimensional vectors, the contents can be plotted in three dimensions by the program Plot3D. In this 3D environment, you can (like a flight simulator) "fly" around your 3D plot. For an example, the following text box contains the point data for a curve in three dimensions.
We send the new text file as an argument to the Plot3D executable. This may look like:
Instead, you can use an "open with" feature in your operating system, which might just be a drag-and-drop maneuver. (Do whatever you need to pass the data file to Plot3D.) The following screenshot shows the output for the example on hand. ![]() |
Live 2D Plotting (return to contents) |
Plot2DLive Commands
The "Live 2D Plot" is a graphical mathematics scratchpad that runs in a SCREEN 12 environment: the dimensions are 640x480, colors go from 0 to 15, and so on. The pixel origin however is changed to the center of the window and Cartesian coordinates are used. Plot2DLive works by constantly checking the contents of a file specified at the command line as an argument when booting the program. As the output window is updated, which takes place roughly once per second, the contents of the file is emptied. Plot2DLive is an input-eating program! Available commands are, the way to load them, and their output is as follows:
![]() |
Plot2DLive Example
A script can export information to a text file during operation using the operator: appendn(filepath,contents). The location referenced by filepath can then be handed to the Plot2DLive executable. In the following example, the intermediate file is named sxamples/Live2DStream.txt.
Be sure to spot the two appendn(,) operators - these are actally "doing" the live updates. ![]() |
Large-Number Calculations
(return to contents) |
Fibonacci Numbers using loop...next
The Nth element of the Fibonacci sequence is defined as the sum of the previous two elements, with starting elements 0 and 1.
|
Fibonacci's 5,000th and 10,000th Numbers
In case you have any use for the 5000th number in the Fibonacci series, the above loop (with the iteration limit changed to 5000-2 and then 10000-2) delivers:
|
Square Root Table
Sxript readily generates numerical data and lookup tables. Following is a table of square roots of the first 60 integrers out to 38 digits (including the sign and the decimal).
|
Pi as Nested Radicals
There are many methods out there, some good and some not, for calculating many digits of Pi. In this example I sacrifice some efficiency for much "interestingness" by using the formula: ![]() After a bit of churning, the following program finally produces a number for Pi, truncated appropriately.
|
Golden Ratio
The golden ratio is a number that occurs (empirically, not as much deductively) all over nature. It's defined this way: divide a line into two parts such that the longer part divided by the smaller part is equal to the whole length divided by the longer part. There are several ways to attain the golden ratio as a decimal, but for demonstration purposes, here I use a first-order Newton's method. The initial guess is 1.4, and the accuracy is set to 35 digits. The script and corresponding output is embedded below.
|
Pi to 100,000 digits
Too many?
|
2014! = 2014 * 2013 * 2012 * 2011 * ... * 2 * 1
It was a good year to create something...
|
Pascal Triangle
... no ordinary triangle.
|
Shortcut to the Fibonacci Sequence
An excerpt from Futility Closet, published June 28, 2015: " Divide the number 999,999,999,999,999,999,999,998,999,999,999,999,999,999,999,999 into 1 and express the result as a decimal expansion, and you'll find the Fibonacci sequence presented in tidy 24-digit strings. " (Note the 8 in the middle of that giant number.)
|
Recursive Functions (return to contents) |
Recursive Factorial Functions
A function whose definition contains itesef is a recursive function - a simple example being one that computes the factorial of an integer. Consider the following definition:
If the argument {x} contains the value +1.0, the calculation is complete, and control is passed to the anchor done. If {x} is anything besides +1.0, the variable ans (initialized to +1.0) is recalculated by ans=x*rec(x-1). Notice that rec, the function we are building, is called at this step. It's not quite circular reasoning, hence the name "recursive". The larger the argument {x}, the deeper the function calls to rec become. Eventually, {x} decreases to +1.0, and recursion stops. Meanwhile ans holds the value x-factorial. A simpler version of the recursive factorial makes use of two print_ statements instead a "helper" variable analogous to ans:
Yet another factorial function makes use of protective double quotes that are used with the iff( ) operator, as in:
|
Fibonacci Numbers using Recursion
The Fibonacci Numbers begin with the sequence (0,1), and then the next number is always the sum of the previous two. The most efficient way to determine many Fibonacci numbers is to use variable storage in a large loop...next structure. A more interesting, yet slower method for determining the Fibonacci numbers deals purely in functions. Consider the following set of instructions (output suppressed):
When executed, the above script returns the sequence (0,1,1,2,3,5,8,...). This is nice, but you can see the complete mess involved with trying to type the input needed to attain more and more numbers. It would be nice to define a kind of function that does the messy work, relieving the programmer of it, without resorting to any kind of loop. The following recursive function fib does the job - it returns the Nth Fibonacci number.
|
String Permutations
A classic problem in computer science courses is the "permutations of strings" problem: Suppose you're given a string, say "BAZ". Write down a recursive function that returns the permutations of "BAZ". In this case, the answer is "BAZ, BZA, AZB, ABZ, ZBA, ZAB". (There are always N-factorial permutations for a string of N characters.) The problem is solved in the code blocks below. Shown first is BASIC code, and following is the equivalent in Sxript. The program outputs are identical (up to formatting).
|
Ackermann Function
The Ackermann function is an example of a total computable function that is not primitive recursive: ![]() Expressed in Sxript, the Ackermann function (followed with a fast-converging example) reads:
|
Combinator
Pushing toward high-minded concepts... You can get rather egghead about all this, so the problem will be posed and solved, keeping the level of abstarction to a mimimum. Suppose you are limited to using a subset of Sxript (or any language), in where you are not allowed to use variable storage, function definitions, loops (which imply variable storage), and let alone recursive function calls, which are obviously forbidden. The question is, can you still use the language to write programs? The answer is yes, provided the language being used supports functional programming, with anonymous functions (aka lambda expressions) being the key. In the example below, you can see the "nuts and bolts" of the standard factorial function, using none of the usual conveniences that we're deliberately avoiding.
The structure surrounding the `factorial' aspect is called a combinator, where this particular example is specialized for recursive functions. Simply install new guts to compute say, the Fibonacci numbers (for convenience the whole construction is wrapped up as a function):
Why not treat the Ackermann function the same way?
|
Fractals and Turtle Graphics (return to contents) |
Sierpinski Triangle
Cool fact: Start with the Pascal triangle and choose two different colors for the odd and even entries. The Sierpinski triangle emerges. Of course, that's not what's done here. Below is a translation of a "fractal" demo found in the QB64 "samples" folder. The image below was generated using Plot2DLive.
|
Fractal Fern
This program is a more-or-less direct translation of the famous "fractal fern" demo found in any good QB samples collection. The image below was generated using Plot2DLive.
|
Mandelbrot Set
The Mandelbrot set is a famous subset of the complex plane. The script below is interpreted from Antoni Gual's 9-line program (2003). Due to the inefficiency of the algorithm employed, it's admittedly slow-running on a QBasic implementation of Sxript. Below, the image on the left shows a few thousand iterations of the algorithm using Sxript (plotted in Plot2DLive). The image on the right was generated with QB64 over about half a million iterations.
|
Turtle Graphics: Flower
Tell a turtle to move forward, turn left, move forward, turn left, and so on until he completes a circuit. Tell him to turn left an extra time, and trace out another curcuit. Repeat these instructions for several iterations to produce the shape below. This particular example showcases an etch-a-sketch-like plotting system named "Turtle Graphics". You are equipped with one tracer line, which understands instructions for moving forward, moving backward, and changing velocity (step distance or angle). These constructs don't exist as Sxript language primitives, but instead are defined on the fly as seen below.
|
Koch Line Fractal
Consider a straight line. Next, where ever you see a straight line, kink it such that the middle of the line comes to a 60-degree crest. Repeat these instructions four times, and the Koch Line Fractal emerges. (The actual graphics are traced by the "Turtle" method described above.) The instructions for the Turtle plot are generated by the rule: That means, in words, "a step forward is transformed into a step forward, turn left, step forward, turn right, turn right, step forward, turn left, step fowrard. All turns are 60 degrees. This process, iterated 4 times, generates the instructions: RFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRF LFLFLFRRFLFLFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFLF LFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFLFLFRRFLFLFLFRR FLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFL FLFLFRRFLFLFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRF LFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFLFLFRRFLFLFLFRR FLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFL FLFLFRRFLFLFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFLFL FRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFLFLFRRFLFLFLFRRF LFRRFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLFRRFLFRRFLF LFLFRRFLFLFLFRRFLFLFLFRRFLFRRFLFRRFLFLFLFRRFLF The turtle's walk (flight, really) is plotted below.
|
Koch Snowflake
The initial state of the Koch Fractal (see above) need not be a single straight line. Start with an equilateral triangle, and get a snowflake:
|
Calculus and Differential Equations (return to contents) |
Derivative of a Math Expression
Anyone who has been confronted by Calculus 101 has heard of the derivative, which is the slope of a mathematical expression f({x}) at a given point {x}. As a generic function, the simplest expression for the derivative reads:
The function deriv evaluates the mathematical expression f({x}) at two points near {x}, and then divides by the distance between them. The "resolution" of the derivative is set by variable {z}. No reason to stop there. A second-order approximation for the first derivative gives better accuracy (in many cases), as given in the following definition:
To see each derivative in action, consider the polynomial equation f(x)=3x^*2+x*(4-x). The analytical derivative of this Function reads f'(x)=4*(x+1). It follows that f'(3)=16. Numerical validation of this claim is in the code box below:
|
Numerical Problem Solver
Here we construct a set of tools for finding the real root(s) of nearly any mathematical expression. We'll pull together many of the ideas mentioned above, plus several ideas from calculus that were not explicitly mentioned. Consider a function problem of one variable {x} that obeys: ... where x* is unknown and must be determined. For example, to compute the cube root of seventeen, you might write func[problem]={x}^3-17, which evaluates to zero when x=x*. Let us take a much juicier polynomial though:
To proceed, we'll need the "derivative" (the slope-at-a-point) function defined above, which reads:
The next step involves, very loosely speaking, solving the above equation for {z} for a special case of the numerator. Relabeling variables, we land at a first-order Newton/Euler expression that can be iterated:
The itersolve function takes three arguments: {x} contains the name of the problem being solved (literally named in this case), {y} is a "guess" solution to problem, and {z} is the resolution on the derivative. The purpose of itersolve is to take the function {x}, evaluate it with argument {y}, do the same thing with the derivative of {x}, take the ratio of the two, and subtract that ratio from the original {y}. The result is a "better" guess {y} than what you started with. Of course, nobody wants to iterate a function by hand, so a third tool shall be constructed, and we'll name it solve, a function takes three arguments, respectively: a problem name, a guess, and a number of iterations:
(Note that the resolution on the derivative is fixed at +0.001.) Now, returning to the problem on hand, let's wrongly suppose the answer is +0.5, and let Sxript improve the guess +10.0 times. We simply write:
... which isn't bad! Check out Woflram Alpha's treatment of the same input (real roots only). To solve other problems, just redefine problem and choose a good guess. The rest stays the same. For easy export and/or quick use, the following box contains the for essential lines to establish the numeric solver. Pay clsoe attention to the role of the lambda expression.
|
Differential Equations
Consider a particle located in three-dimensional space, subject to a uniform gravatational field in the downward direction. In addition, a vertically-aligned magnetic field acts on the particle (the particle must be charged), causing a circular motion. Finally, a "false friction" force is introduced, which pulls the particle toward the central axis. Question: What is the trajectory of the particle at all times? The following script answers the question; the output of which can be viewed with Plot3D.
|
Damped Projectile Motion
A simple demonstration of a confined rubber ball in a gravational field.
|
Experimental Error Propagation
This is a story about two resistors...
|
Symplectic Integrator
(This section deserves a good discussion with plenty of links.)
|
Vector and Matrix Calculations (return to contents) |
Basic Vector Operations
The following code boxes illustrate (loosely) the ideas of manual vector creation, automatic vector creation, manipulating elements, vector mapping, lazy vector addition, and hard evaluation.
|
Magnitude of a Vector
Two techniques for computing the numerical magnitude of a vector are demonstrated in the following code box:
|
Geometric Series
The components of a vector created by the vecn(...,n) operator consist of integers spanning from 1 to the dimension n. Exploiting this, we sum the first n terms of the geometric series based at 1/2:
|
Real Roots of a Polynomial
A specialized function has been developed to determine the real roots of an n-order polynomial, so long as a sufficient guess is provided that is in the basin of attraction of the answer, which is approximated by a first-order iterative Newton's method. For instance, the polynomial: ... has a real root in the same basin of attraction as the guess value +0.3, determined by the statement:
The above result isn't bad for an approximation. The true answer (for this particular root) is -1.0. |
Basic Matrix Operations
The following code boxes illustrate (loosely) the ideas of manual matrix creation, automatic matrix creation, manipulating rows / columns / elements, etc.
|
Matrices in Chains
Consider a 2*2 matrix. The top row has entries <1;2>, and the bottowm row holds <3;4>. Next, add 6 copies of this matrix together. What is the result? Repeat for multiplication.
Note that the first of the statements is wrapped in meval( ). (Otherwise the components aren't mathematically evaluated; they appear as long sums in this case.) One way to get around this is to curry, which amounts the making the definition func[madd2]=meval(madd({x},{y})). Using this, the meval( ) wrapping is not needed. (Of course we're just showing off. The same can be accomplished using:)
|
Linear Systems of Equations
Consider the set of three euqations and three unknowns:
... where your job is to solve for x, y, and z. One solution to this problem involves pencil and paper, in which case you might solve for x or y first, try to get all the algebra right, and eventually you'd have the answer... hopefully... A matrix lets you do something better. First, recast the problem into the row echelon form, in where the "numbers" from the problem are written into a dimension N,N+1 matrix, where N is the number of equations/variables.
To solve the system of equations, a few linear algebra moves must take place. The matrix must go from to row echelon form (above), to upper triangle form, and then to (system) diagonal form, and finally to normalized diagonal form. The answer is read off as a column vector.
The answer to this problem can be read off from the matrix above. You can verify that the solution to this system is: Of course, it's more economical to stuff all of the linear algebra into one function, and then the problem can be solved without having to name the matrix:
|
Comparison and Sorting (return to contents) |
String Comparison
Beyond the simple check for exact equality, comparison between strings is ambiguously defined in the general case. We shall proceed with the "rule" that strings are composed of individual ASCII characters from left to right. For a string to be "greater" than another string, it's left-most ASCII-represented chracter must have a higher index than that of the other string's leading character. If the two leading characters are equal, focus shifts one space to the right until a difference in the strings is found. The exact behavior of a string comparison routine is up to the programmer who designs it. Following is an example script that shows the definition and use of a function that takes two string arguments, and returns the "greater" of the two strings, alphabetically.
A varation on the "strcmp" function might involve not returning an actual string, but perhaps +1.0 if the first string is "greater" than the second, and zero otherwise. In that case, you might write:
|
Bubble Sorting
Bubble sorting is perhaps the least efficient method for sorting a list containing strings or numbers, but to it's credit, is extremely easy to code. Consider the following function, designed to sort a list of numbers:
In analogy to "bubnumsort", we can write "bubstrsort" for strings. Out new string sorting function shall be designed to make use of the function strcmp2 defined previously. Instead of re-defining the function, we'll execute the text file containig the definition. See the code box below.
|
Phrase Translator
The following example is coded to showcase flexibility, not speed.
|
Misc. Programs (return to contents) |
Example: QB64 Rotation Matrix
The following QB64 program demonstrates the creation and repetitive use of a rotation matrix. The matrix itself and it's calling function are defined in the first two EvalInput$() operators. A vector named cat is the thing that rotates, imitating a clock needle.
|
Cover Images
Following is the code used to generate the 3D trig curve at the top of this page.
|
Geometry Problem: Finding a circle from three points.
Given three position vectors that define the rim of a circle, determine the equation of the entire circle.
|
Conway's Game of Life
The famous invention from 1970. If you weren't concinved already, this roundaboutly proves the "Turing Completeness" of the Sxript language.
![]() |
Special Keywords (return to contents) |
Non-Embedded Special Functions
There is a subset of functions that must be called on their own. These are called "non-embedded" functions. acc(x) (set digit precision)
acc? (global precision check)
accd(x) (set double precision)
accd? (double precision check)
appendn(name, record) (add record to file)
int< f([x]) ; lowlimit ; highlimit ; step > (one-dimensional integration)
plot< f([x]) ; lowlimit ; highlimit ; step > (plot f(x) SCREEN 12)
plotascii< f([x]) ; lowlimit ; highlimit ; step ; recipient > (plot f(x) ASCII)
sci(x) (toggle scientific notation)
sci?() (report scientific notation toggle)
exe('file) (execute program)
|
Numerics (return to contents) |
Math Operations
+ (add) - (subtract) * (multiply) / (divide) Precision: HIGH
!(x) (factorial) Precision: CONDITIONAL
\(x,y) (integer division) Precision: HIGH
abs(x) (absolute value) Precision: HIGH
choose(x,y) (combinatorial choose operator) Precision: CONDITIONAL
dice(x) (random integer) Precision: DOUBLE
dom(x,y) (return larger number) Precision: HIGH
ee(x) (digits of e) Precision: HIGH
exp(x) (Euler exponent operator) Precision: CONDITIONAL
inrange(a,x,b) (if in range) Precision: HIGH
intg(a) (integer operator) Precision: HIGH
kron(x,y) (Kroneker delta) Precision: HIGH
ln(x) (natural logarithm operator) Precision: HIGH
log(x) (base-10 logarithm operator) Precision: DOUBLE
mod(x,y) (modulus operator) Precision: HIGH
phi(x) (golden ratio) Precision: HIGH
pi(x) (digits of pi) Precision: HIGH
pow(x,y) or x^(y) (decimal exponent operator) Precision: DOUBLE
powi(x,y) (integer exponent operator) High Precision (Fast): YES
powl(x,y) (large exponent operator) Precision: HIGH
prime(x) (prime number check) Precision: CONDITIONAL
rnd(x) (random number) Precision: DOUBLE
smaller(x,y) (if smaller) Precision: DOUBLE
sqr(x) (square root) (x >= 0) Precision: HIGH
num(a,y) (variable store) Precision: HIGH
numn(a,y) (evaluated variable store) Precision: HIGH
|
Trig Functions
cos(x) ( cosine )
acos(x) ( arc cosine )
sec(x) ( secant )
asec(x) ( arc secant )
cosh(x) ( hyperbolic cosine )
acsh(x) ( arc hyperbolic cosine )
sin(x) ( sine )
asin ( arc sine )
csc(x) ( cosecant )
acsc(x) ( arc cosecant )
sinh(x) ( hyperbolic sine )
asnh(x) ( arc hyperbolic sine )
tan(x) ( tangent )
atan(x) ( arc tangent )
tanh(x) ( hyperbolic tangent )
atanh(x) ( arc hyperbolic tangent )
d2r(x) ( degrees to radians )
r2d ( radians to degrees )
|
Strings (return to contents) |
String Operations
$(bar) (literalize string name)
stadd(a,b) (combine strings)
stchar(a,x) (return character)
stkron(a,b) (Kroneker delta for strings)
stlcase(a) (convert to lowercase)
stleft(a,x) (left substring)
stlen(a) (string length)
stmid(a,x,y) (mid substring)
stperm(a) (native string permutation)
stright(a,x) (right substring)
string(a,b) (string store)
sweep(a,b) (sweeping replace)
stucase(a) (convert to uppercace)
|
Vectors (return to contents) |
Vector Operations
v(a) (vector name -> literal operator)
vect(a,y) (create vector manually)
vecn(bar,N) (create vector automatically)
vadd(a,b) (lazy vector addition)
vapply(foo,baz) (apply function to vector)
varg(foo) (vector argument count)
vcadd(a) (vector collapse by addition)
vcmul(a) (vector collapse by multiplication)
vcross(a,b) (cross product)
vdot(a,b) (dot product)
velem(foo,N) (vector component selection)
velev(foo,N) (vector component evaluation)
veval(foo) (vector component evaluation)
vins(foo,N,baz) (insert new element)
vmap(cat,play,dog) (apply function of two vectors)
vpasc(N) (Pascal triangle)
vrepl(foo,N,baz) (replace single element)
vshrink(foo,N) (delete one element)
vstack(a,b) (stack two vectors)
vsub(vec,A,B) (return vector subset)
reduce(foo,baz) (reduce a list)
|
Matrices (return to contents) |
Matrix Operations
... (...)
... (...)
... (...)
|