

                          An Introduction to UBASIC
                                     (Written for version 8.84)

                                       by Seymour Haber    (Copyright 1996)


Contents:

      Lesson 1:   How to escape from bad situations.  Starting UBASIC.
                Writing a program.  Displaying, running, and printing a
                program.  Saving a program (to disk) and loading (from disk).
                Some editing of programs.  Precision of numbers in UBASIC.
                Point.  Immediate mode.

      Lesson 2:   Input.  Function subprograms.  For-next Loops.  If-then-
                else-endif.  Print using.  Graphics: screen, view, window,
                pset, line, colors.  Some more editing.

      Lesson 3:   Subroutines.  Local variables.  While-wend loops.
                Function-name variables.  Append.

      Lesson 4:   On-line help.  Colors.  Indexed arrays of numbers (vectors,
                matrices).  Dim.  Read and data.  Word.

      Lesson 5:   Nested loops.  More about subroutines.  Complex numbers.
                Circle.

      Appendix IA:   A list of UBASIC instructions.

      Appendix IB:   About UBASIC's manual.  Printing it (using PCBOOK).


      (This tutorial is written for people using UBASIC on IBM-type personal
computers.  Parts of it may not apply to other types of computers.  It may be
copied and distributed freely for individual use; it may not be sold without
permission of the author.)









Lesson 1:  Getting out of trouble.  About UBASIC.  Starting.  Writing a
            program.  Editing.  Immediate mode.


      Preface about computer mishaps: In using UBASIC - or any other
computer facility - you may get into a situation where the computer is doing
something you don't want it to do, and you want to stop it.  Or perhaps the
machine appears to be doing nothing, but doesn't respond to anything you
type at the keyboard.  This very rarely means that anything terrible has
happened, and the usual ways to get out of the situation are:

      1.  DO NOT remove a disk from the floppy-disk drive, if the disk drive
light is lit.

      2.  Key Ctrl-Break.  That is, hold down the Ctrl key and press the
Break key.  That may stop a program that is running, and restore the screen
and keyboard to normal status.

      3.  If 2. doesn't do the job, key Ctrl-Alt-Delete.  That is, hold down
both the Ctrl and Alt keys and press the Delete key.  That may stop whatever
is going on, and "reboot" the machine.  That amounts to restarting the
machine, and whatever work is in the machine and has not been "saved to
disk", is lost.  This is called a "warm boot".

      4.  If 3. doesn't do the job, and there is no smoke coming from the
machine - or other indication of catastrophe - see if you can find someone
knowledgeable to help you.

      5.  If 4. doesn't do the job, press the machine's reset button.  The
machine should stop whatever it's doing, and reboot; in effect it's turning
itself off and then turning on again.  This is called a "cold boot".

      6.  If 5. doesn't do the job, turn off power to the machine.  Wait half
a minute and turn the power on again.  If the machine then works normally,
fine.  If not, you have a problem that needs to be solved.

      It is easy to get into bad situations.  It may happen as the result of
some unforseen action of a program that you have written, or sometimes when
trying to print while the printer is turned off, or even because of
accidentally striking a key.  Doing any of steps 3-6 will erase the work that
you have been doing from RAM (the computer's active memory). A considerable
amount of your work may be lost if it has not been stored away.  So it is a
good idea to frequently "save" your work to disk.  We'll see how to do this in
UBASIC, and how to retrieve the saved material.



      Preface about UBASIC:  UBASIC is a programming system designed for
mathematical work.  It is especially suitable for number theory and for
numerical analysis.  A major feature is that it allows the use of numbers with
up to 2,600 digits, approximately.  Another valuable feature is that it works
routinely with complex numbers.

      UBASIC is in some ways an old-fashioned BASIC like the original
Dartmouth BASIC or GWBASIC - and in some ways a modern one like Turbo
Basic or TrueBASIC or QBASIC.  It is quite different from some newer
languages such as Visual BASIC, whose main purpose is designing user-
interfaces of a certain style.  One old-fashioned feature is that program
lines must be numbered.  One modern feature is that subroutines may have local
variables.

      UBASIC is a DOS, not a Windows or OS/2 program - as of the time of
writing.  If you are accustomed to working in Windows or OS-2 you may be
able to run it in a DOS window.  Or else you may be able to exit from
Windows or OS/2 to DOS.

      UBASIC is freeware, through the generosity of its original developer
Professor Yuji Kida and of others who have contributed to it.  It is usually
distributed as a compressed file - e.g. UBIBM884.ZIP - accompanied by the
decompression utility UNZIP.EXE (or PKUNZIP.EXE) and auxiliary files.  UBASIC
is constantly under development - removing bugs, adding features.  Users of
FTP may obtain the latest version from
                        rkmath.rikkyo.ac.jp   ,
where it is in the directory /ubibm.  (As of the time of this writing the
files, there, that are absolutely necessary for running UBASIC are
ubibm884.zip, ubhelp.zip, ubiapl94.zip and of course unzip.exe.)

      There is much more to UBASIC than will be taught in this Introduction.
The main source of further information is an informal manual that is contained
in the file UBHELP.XXX (one of the files that you will get by unzipping
UBHELP.ZIP, as described below).  That manual is described in Appendix IB,
together with 2 ways of printing it out.  The manual has also been
incorporated in an on-line help system whose use is described in Lesson 4 of
this Introduction.  There is also a list of UBASIC's instruction words,
grouped by subject, in Appendix IA; it may help you know what to look up in
the manual.

      Installing UBASIC on your computer:  UBASIC is often distributed on a
floppy disk and I shall suppose that you have it in that form.  The disk
contains a number of files whose names end with ".ZIP".  Those are "archive"
files and each one contains a set of files of various sorts, compressed.  There
is also a file named UNZIP.EXE (or PKUNZIP.EXE) that extracts and
decompresses the contents of .ZIP files.  The archive files on the disk that I
have are UBIBM884.ZIP, UBHELP.ZIP, UBIAPL94.ZIP, UBI874GR.ZIP, and some others.
UBIBM884.ZIP contains most of the UBASIC working environment - the interpreter,
editor, etc.  A few other files that UBASIC needs - UBCONST7.DAT, UBH.UB,
UBH.BAT, UB.MAC, MAKEUBB.BAT, UBHELP.DOC and UBHELP.COM - are in UBIAPL94.ZIP.
UBI874GR.ZIP contains various graphics programs written in UBASIC, including
PLOT3D.UB which is a useful plotter of functions of 2 variables.  Most of
UBIAPL94.ZIP and all of UBIAPL95.ZIP, PPMPX.ZIP, UBMALM.ZIP and UBPPMPQS.ZIP
consist of UBASIC programs, mostly number-theoretical.  For a minimal
installation you need only decompress UBIBM884.ZIP, UBHELP.ZIP and UBIAPL94.ZIP
- which also contain some text files (particularly READMEUB.884 and
UBHELP.XXX) that give you information about UBASIC.

      To install UBASIC on your hard disk, first set up a directory in which
it is to reside.  I'll take this directory to be \UB884, but you may use any
name you wish (that is acceptable to DOS).  Copy UNZIP.EXE and UBIBM884.ZIP
into that directory, from your floppy, and any other .ZIP files that you wish.
Then, at the DOS command prompt, type in
                            unzip ubibm884
(ending by pressing the Enter key).  The 3 files in UBIBM884.ZIP will be
extracted and placed in \UB884.  Do that, also, with any other .ZIP files you
choose; after that you may delete the .ZIP files and UNZIP.EXE if you wish to
economize on hard disk space.

      It is also possible to install UBASIC on a 1.44MB floppy and work
entirely in that floppy.  Just replace "\UB884" in the instructions above, by
the working floppy.  If you do have a hard disk, that might be done most
quickly by first installing UBASIC on your hard disk and then copying that
directory, in toto, to your working floppy.


       Now let's start: If UBASIC is installed on your hard disk (C:, say), get
your machine to display the DOS prompt and switch to the directory that
UBASIC is in.  Type in
                             ubibm32
(ending with keying the "Enter" key).  That should get you the UB working
screen.

      If your UBASIC is installed on a floppy disk, insert that disk into the
A: drive (say). Switch control to the A: drive (by typing in "A:") (concluding
with pressing the "Enter" key , of course) if your machine is already
displaying a DOS prompt; or first getting your machine to display a DOS
prompt if it isn't.  Type in:
                              ubibm32
(and press "Enter").  That should get you the UB working screen.

      Ending a session of using UBASIC, and returning to the DOS prompt, is
done as follows:  Use arrow keys to move the cursor to a blank line
somewhere on the screen, and type in
                       system
(followed by the Enter key).  The program that you are working on will be
lost, unless you have already saved it to disk as described below.

      Now key in the following program, which solves quadratic equations: (at
the end of each line press the Enter key.)
                  10  a=1
                  20  b=-1
                  30  c=-1
                  40  discr=b*b-4*a*c
                  50  r1=(-b+sqrt(discr))/(2*a)
                  60  r2=(-b-sqrt(discr))/(2*a)
                  70  print r1, r2
                  80  end
If  you make a mistake in any line, retype it.

      When you've finished, press the F4 key and then the Enter key, and a
"listing" of the program should appear on the screen.  Notice the ways in
which the listing differs from what you typed!  If any line seems wrong to
you, retype that line and "list" the program again.  (You may retype the
line - just be sure to include the line number - at the bottom of the screen
or on any line of the screen that is empty.)

      Press the F6 key - noting what happens on screen - and then
                   demo1
and then the Enter key.  That stores ("saves") the program on your disk, as
a file named DEMO1.UB .
      Now "run" the program by keying the F5 key.  Two numbers should
appear on the screen and they should be the roots of the equation
                       x*x-x-1=0.
That's the general quadratic equation ax*x+bx+c=0 in the case a=1, b=-1 and
c=-1.

      What UB operations have you used?  They are:
        =    Assignment. In UB "=" is an operation, not a statement.  "A=1"
                  means "let the variable A have the value 1".
         *   Multiplication.
        -    Subtraction.
         /   Division.
      Sqrt   Square root.
      Print  Display (what follows) on the computer screen.
       (,)   Set the order in which operations are done, in the usual way.
        ,    The comma, in a print instruction, spaces the items to be
                   printed in a certain way.  An alternative is the semicolon,
                   which produces a tighter spacing.
      End    Tells UB's internal operations that no further instructions are
                   to be carried out.


      Experiment a little.  For example, change line 10 to
                             A=3   .
That can be done 2 different ways: You can simply type in the new line 10,
including the line numbers, on a blank line anywhere on the screen.  Or else
you can:
      List the program, so that line 10 is shown.
      Using arrow keys, position the cursor on line 10, under the 1 in the
         instruction "A=1".
      Press the 3 key, changing the 1 to a 3.
      Press the Enter key, to finalize the change.
Run the program to see the new roots, which should be roots of
the equation 3x*x-x-1=0.  You can check them by pencil and paper and
calculator.

      After you've made changes you can retrieve ("load") the  original
program from the disk by keying the F1 key, then demo1, then Enter; and
you can see that it's back by listing it.

      If you wish to have the program printed on paper, type in (on an
empty screen line) the instruction
                       llist   .
And if you ever want a program's output to be printed on paper instead of
displayed on the screen, replace the instruction "print" by "lprint".

      (Why the "l" ?  Well, originally BASIC was used on a time-sharing
system, with Teletype machines serving as terminals.  There were no screens
and everything appeared on paper, so "print" meant what it means in English.
Later video terminals replaced the Teletypes and everything appeared on
screen, so "print" came to mean "display".  But output on paper ("hardcopy")
was still desirable at times, so an instruction was needed to make the central
computer, that was serving all the terminals, print on paper.  The central
computer's printer was a fast line printer - it printed all the characters on
each line simultaneously - so the letter "l" from "line printer" came to be
used.)

      All your answers were displayed with 19 decimal places (unless they
were integers).  UB can change that.  With the original demo program back on
the screen, type in the line
                       5 point 2
(You can type it on any blank screen line, and list the program to see that
it's been put in its right place.)  Now run the programs.  Change the "2" in
line 5 to "10" and run the program again.  "Point" is an instruction that
tells UB how many "words"- a word is 2 bytes - to use for the fractional parts
of numbers.  In effect it tells UB how many digits to carry along, to the
right of the decimal point, in storing and in displaying numbers.   Each word
allows for about 4.8 digits, so that "point 10" give you 48 decimals
precision.  The default is 4 words or about 19 decimal places.

      UB can also do arithmetic without your writing a program.  Move the
cursor to a blank line toward the bottom of the screen and type in
                        print sqrt(2).
You got the answer right away.  When you enter a UB instruction without a
line number you are working in "immediate mode" - the instruction is carried
out as soon as you key Enter at the conclusion of the line.


      Immediate mode has a very useful feature; you have available the
current values of all the variables in the last program that you ran and can
use them to check on what happened.  Type in
                       print r1
and you'll see the value of r1; type in
                  print r1*r1-r1-1
and you'll see whether r1 was really a root of x*x-x-1=0.

      Let's add to demo1 a line giving its name and the date it was written.
Type in
            1 'DEMO1    (the date)
and list the program to see it's in place.  An apostrophe at the beginning of
a UB line means "remark"-i.e., the line contains no operations but only
information for the reader ("internal documentation").  The abbreviation
"rem" may be used instead of an apostrophe; UB does not accept the full word
"remark".

      What if we wanted to add another line to the program, placed before the
line we've just added?  We couldn't - no earlier line numbers are available.
But all is not lost.  Just type in (in immediate mode) the instruction
                             renum
and list the program again.  The line numbers now start from 10 and go by
10's - there's plenty of space for new lines.

      Save this final version by typing in
                       F6 demo1          (here "F6" means the F6 key)
and giving a "y" response to the question you are asked.

      We haven't yet used the operation +.  Type in
                        new .
Your program vanishes - you can check by trying to list it - and UB is ready
for a new program.  Type in, but DO NOT RUN:
                       10  'DEMO2    (the date)
                       20  a=1
                       30  print a
                       40  a=a+a
                       50  goto 30
                       60  end
List the program, to check that you have it right.  DON'T run it yet.

      Line 40: "A=A+A" ??  That means: Assign A a new value which is (the
 old value of A) plus (the old value of A).  That's doubling A, via addition.

      Line 50: "goto 30".  That's a "control" instruction.  UB ordinarily
executes instructions in the order in which they appear in the program.  But
this instruction tells UB to go back to line 30, execute the instruction
that's there, and proceed from there.  So when this program is run the lines
will be executed in the following order: 10 20 30 40 50 30 40 50 30 40, ... .
The program won't ever stop!  (Until something goes wrong.)  But you can
manually stop it by keying Ctrl-Break (as in step 2. Of the Preface about
computer mishaps).  Locate those keys to be ready to break the run, and
press the F5 key.  Break the run.  What are the numbers being displayed?
(You can "pause" the run by the Pause key.  Pressing any other key then
makes the run resume.  Can you key Pause fast enough, after keying F5, to
see the first few numbers produced?)


   Features learnt in Lession 1:
      =, +, -, *, /, sqrt, (,), comma, apostrophe
      Print, lprint, end, goto
      Load (F1), List (F4), Run (F5), Save (F6), llist
      Pause, Ctrl-Break
      Point
      Immediate mode
      rem
      renum
      new
      a little bit about "editing" programs.
     Lesson 2:  Function subprograms, Loops, Conditional instructions,
                  Graphics:

     We're going to calculate some values of two functions
                       f(x)=cos (3 arccos x)
                       g(x)=4x^3-3x
and draw graphs of those functions.  ("x^3" means x-cubed.)  Get into UB and
type in the following program:
                       100  'DEMO3     (date)
                       110  input "x=";x
                       120  ? fnF(x)
                       130  end
                       140  '
                       200  fnF(x)
                       210  return (cos(3*acos(x)))
     List the program.  Notice that the question-mark you typed in line 120
has turned into the word "print".  That's a handy keystroke-saver, especially
in immediate mode.

     Run the program (by pressing the F5 key).  What happens as a result of
line 110 is that the line
                       x = ?
appears on the screen.  The "input" instruction tells the machine to wait for
something to be entered from the keyboard, and to make that something into the
value of the variable x.  The "x = " part is called the prompt - the UB system
displays it on the screen, adding a question mark, to tell you what the
machine is waiting for.  (Waiting through millions of cycles!  Can't you be a
bit faster?)

     Answer the question by typing
                       .3
(followed by the "Enter" key, of course).  A new number appears on the screen.
It  should be cos(3 arccos(.3)).  Is it?  (In checking by calculator, set your
calculator to express angles in radians.  That's what UB does.)

     Run the program again, giving it a different value of x (between -1 and
1, of course).

     In immediate mode, type in
                       ? fnF(.3)      .
Your function is now available in immediate mode too.

     Look at line 130.  Each run stops there.  So how did the machine know
what "fnF" means; it wasn't defined till later.  Well, the UB system looked
ahead when starting the run.

     Your machine is, for now, a calculator for the function
                       cos(3 arccos x)
which was defined in lines 200 and 210.  Note UB's syntax here:  function
definitions start with a line giving the function name and its independent
variables in a fairly natural form, except that the name must begin with the
letters "fn".  The definition ends with a "return" instruction, that gives
the function value.

     (Some programming terminology:  Lines 110-130 constitute the "main
routine" or "main program".  Lines 200-210 make up a "subprogram",
specifically a "function subprogram".  The main routine "calls" the function
subprogram simply by using its name in an instruction line (line 120); the
function subprogram "returns" a value to the main routine.)

     The variable X in lines 200-210 is a "bound" or "dummy" variable.
Change the X's in those 2 lines to Y's (without making any change in lines
110-120) and run the program again.  It works the same as before.

     Let's add in our second function.  Add these lines to the program:
                       220  '
                       300  fnG(x)
                       310  return (4*x*x*x-3*x)
and change line 120 to
                       120  ? fnF(x), fnG(x).
Run the program again, with x=0.3.

     g(0.3) came out the same as f(0.3) - apart from roundoff error.  Are the
two
functions the same?  Let's see if they're equal for x=0, 0.1, 0.2,..., 1.0 -
all in one run.  Type in the following program lines:
                       105  '
                       110  for i=0 to 10
                       115  x=i/10
                       125  next i
List the program.  The new line 110 replaced the old one.

     Run the program.  The columns are sort of messy, but they do indicate
that the values of the two functions are equal.

     Let's see how the program worked:  lines 115 and 120 were carried out 11
times - for I=0, 1, 2,...,10, just as lines 110 and 125 ordered.  To make this
more obvious to a reader of the program, let's indent lines 115 and 120.
Place the cursor (using the arrow keys) on line 115, between the 5 and the x.
Press the Insert key - the cursor changes shape.  Press the spacebar twice,
inserting 2 spaces.  Key Enter, to register the changed line.  Similarly
insert 2 spaces on line 120.

     Lines 110-125 constitute a "loop" - perhaps the most important of control
structures.  This is a "for-next" loop, which is found in all versions of
BASIC; UB also has some other loop structures.

     In some BASICs we could have simply written
                       110 for x=0 to 1 step 0.1
instead of the lines 110 and 115 that we did write.  UB doesn't allow that -
it requires loop indices to be integers.

     By the way it's about time to save the program.

     We can neaten up the display of the function values, to make it simpler
to compare them.  Change line 120 again, now to
                 120  print X, using(3,4), fnF(X), fnG(X)
(be careful not to leave a space between "using" and "(3,4)") and run the
program.  "Using (3,4)" means that the numbers following the "using"
specification are to be shown as specified.  "Using(3,4)", in particular,
specifies that just 4 digits are to be shown to the right of the decimal
point (rounding is automatic), and 3 spaces are allowed for characters to the
left of the decimal point ("characters", here, meaning digits and the minus
sign, if a minus sign is needed).

     Note the commas before and after the "using" instruction.

     Well, F(x)=G(x), at least for x in [0,1].  You may have recognized them
as the Chebyshev polynomial of degree 3.

     Incidentally, functions as simply defined as these two may be defined in
a single program line.  Instead of lines 300 and 310 we could simply have
written
                305 def fng(x)=4*x*x*x-3*x   .
You might check that by typing in this line and then deactivating lines 300 and
310 by placing apostrophes after the line numbers on those lines ("remming
them out") and running the program.  In this tutorial we shall not use this
feature, we shall stay with the more general fn - return way of defining
functions.  (Single-line function definitions are not available in UBASIC
versions prior to 8.82.)

     Let's extend the range of our computation to [-1,1].  Change the
range of I, in line 110, to 0-to-20, and change the value of X in line 115 to
I/10-1.  Run the program.

     Now let's graph the function - say G(x), which is defined for all x.
This takes some preparation!  We're going to insert a lot of new lines,
so let's renumber what we now have: Type in
                       renum 100,100
and list the program again.  (For listing, try keying the Page Up key,
instead of F4 and Enter.)  Erase line 140 by keying, on an empty line
somewhere on the screen, "140" followed by keying Enter.
Add all the following lines:
                       112  screen 23
                       114  window (-2,2)-(2,-2)
                       132  if i=0 then
                       134  :pset (x,fnG(x))
                       136  :else
                       137  :line - (x,fnG(x))
                       139  endif
and run the program.  You should get a neat broken-line graph of the cubic
polynomial.

     To get back from the "graphics screen" to the editing screen, you should
key F4 and then Return.  The Page Up and Page Down keys won't do it.

     Before I discuss the new instructions, you might want to renumber the
lines and insert spaces to pretty things up (resulting in the listing below),
and save the current version of DEMO3.  I'll assume that you've at least
renumbered the program - so that line 112, e.g., is now line 120.

                 100 'DEMO3       (date)
                 110'
                 120 screen 23
                 130 window (-2,2)-(2,-2)
                 140 for I=0 to 20
                 150   X=I/10-1
                 160   if I=0 then
                 170     :pset (X,fnG(X))
                 180   :else
                 190     line -(X,fnG(X))
                 200   endif
                 210 next I
                 220 end
                 230 '
                 240 fnF(X)
                 250 return(cos(3*acos(X)))
                 260 '
                 270 fnG(X)
                 280 return(4*X*X*X-3*X)

     "screen 23" told UB that you may be doing graphics, and it would be in
standard VGA:  640x480 pixels, 16 colors.  (On some machines - not mine -
"screen  823" would get you higher resolution:  800x600 pixels.)

     "Window (-2,2)-(2,-2)" told UB to set up coordinates in the portion of
the monitor screen that you will be using, and that x is to range from -2 on
the left to 2 on the right while y ranges from 2 at the top to -2 on the
bottom.  Specifying the y range in that order is a bit unnatural, but that is
how "window" works in UB. You can see it more clearly in the next version of
line 130, below.

     "pset (A,B)" means: Place a dot at the point (A,B).

     "line -(A,B)" means: Draw a straight line segment from the last point
previously drawn, to (A,B).

     "if....then" means what you'd expect.

     "else" means: If the condition in the preceding "if" was not satisfied,
do the following.

     "endif" closes off the conditional statements.

     UB's "if" structures are somewhat complicated and deserve reading about
in the manual, and experimentation.  Note the colons starting the program
lines between the "if" and the "endif".

     It's neat getting a graph drawn that fast, but it wasn't that great a
graph.  White on black, no coordinate lines, obviously a broken-line graph.
Let's fix that last defect first.  Change lines 140 and 150 to read:
                 140  for I=0 to 200
                 150  X=I/100 -1
and run the program.  Nicer, and about as fast.

     Let's make it black on white.  For this we need the "view" instruction,
which specifies what part of the monitor screen we'll use for our graph and
what color that part of the screen is to be.  (When we didn't use that
instruction we got the default: full screen, black.)  Add in the line
                 125 view (0,0)-(639,479),15
and also add ",0" to the ends of lines 170 and 190.  Line 190 will now read:
                 190     :line -(X,fnF(X)),0   .
Run the program.  15 is the number for the color white, 0 for black.  Try
some other color numbers - integers, from 0 to 15.

     Let's put in axes and coordinate lines, in colors of varied
obtrusiveness.  To do this handily I'll use some features of UB that won't be
discussed in detail in this lesson.  Add in
                 127  x1=-2: x2=2: y1=-2: y2=2
and change line 130 to
                 130  window (x1,y2)-(x2,y1).
That doesn't change what the program does, but it makes the x and y ranges
available for future use in the form of the variables x1, x2, y1 and y2.
(Note that we've put 4 separate instructions on line 127!  The colons are the
mandatory punctuation for this purpose.  Putting several instructions together
on a single line often aids readability of a program.)  Now add the following
lines:
                135  gosub *GRFPPR(x1,x2,1,y1,y2,1)
                290  '
                500  *GRFPPR(x1,x2,xtick,y1,y2,ytick)
                510  local c,x,y
                520  c=3
                530  if y1<=0 and y2>=0 then line (x1,0)-(x2,0),1
                540  if x1<=0 and x2>=0 then line (0,y1)-(0,y2),1
                550  x=-xtick:while x>=x1:line (x,y1)-(x,y2),c:x=x-xtick:wend
                560  x=xtick:while x<=x2:line (x,y1)-(x,y2),c:x=x+xtick:wend
                570  y=-ytick:while y>=y1:line (x1,y)-(x2,y),c:y=y-ytick:wend
                580  y=ytick:while y<=y2:line (x1,y)-(x2,y),c:y=y+ytick:wend
                590  return
     (A hint for slow typists:  to type in lines 550-580, first type line 550
and list the program to see that it's present.  Then move the cursor to line
550 and modify it to become line 560:  change the second 5 to a 6, delete the
minus sign that follows the first "=" sign, etc.  Don't forget to key the
Return key when you're done.  List the program again.  You'll have both line
550 and line 560!  This is a neat "editing"  feature of UB.  You can go on to
create lines 570 and 580 the same way.)

     Now run the program.  You'll see the axes in blue, and other coordinate
lines in a lighter color.  You'll notice we've only graphed the function for
x between -1 and 1.

     To have more coordinate lines, replace the two 1's on line 135 by 0.1's.
Run the program again.

     The little coordinate boxes are not square.  That's because we don't
have the same physical scale for x and for y.  Lines 127 and 130 do specify
that each of x and y runs from -2 to +2; but line 125 allots 640 pixels to
the x-range and only 480 to the y-range.  Change the number 639 in line 125
to 479, and run the program.  Now the x and y physical scales are closer to
equal.  (They may not be perfectly equal - pixels may not be square!  That is
monitor-dependent.)  But the graph doesn't fill the screen.  A way to equalize
the x and y scales and use the whole screen, is to use different ranges for x
and y, making the x-range about 4/3 the y-range.  To see how that works,
change the first 479 on line 125 back to 639 and change line 127 to
        127  y1=-1.2: y2=1.2: x1=(4/3)*y1: x2=(4/3)*y2
and run the program.  Save the program under the name DEMO3.

     (Unexplained features used in this program:  Subroutines and their
syntax, local variables, colors 1 and 3, while-wend loops.)

     Features learned in this lesson:
           "?" as an abbreviation for "print"
           input, and prompting
           function subprograms
           dummy variables
           using the "insert" key in editing
           for-next loops
           single-line function definitions
           print using
           screen
           view
           window
           pset (a,b)
           line -(a,b)
           line (a,b)-(c,d)
           if - then - else - endif
           color numbers 0 and 15
           horizontal and vertical scale.
     Lesson 3:  Subroutines, while/wend loops, and more editing:

     We've studied some 20 features of UB in each of the preceding lessons -
how much more is there to learn?

     Well, UBASIC is a language.  It's infinitesimal compared to any natural
language, but natural languages take years to learn well, and UBASIC takes
more than 2 hours.  We'll go on for 3 more lessons.

     In this lesson I'll start with an explanation of lines 500-590 of DEMO3,
and line 135.  Lines 500-590 make up a "subroutine" and line 135 "calls" that
subroutine.  A subroutine is a program in itself, that is part of a larger
program.  Certain of the activities that we wanted DEMO3 to do - drawing axes
and coordinate lines on the screen - were set off from the rest of DEMO3 by
being put into this subroutine.  Later we'll discuss why this was done.

     A subroutine starts (in UB) with an asterisk, a name, and a list of
variables enclosed in a parenthesis.  The name of our present subroutine is
"GRFPPR" (for "graph paper").  Its variables are x1, x2, xtick, y1, y2 and
ytick.  They are all numerical variables (in this case) and their values,
which the main program sends to the subroutine when calling it in line 135,
tell the subroutine just what it needs to know to draw the graph paper:  the
x-range (from x1 to x2) and the x-spacing of the vertical coordinate lines
(xtick), and similar y information.

     Start UB, load DEMO3, list it, and use the Page Up key to get line 135
on the screen.  Note that four of the six numbers being sent to the subroutine
have the same names as they have in the subroutine definition on line 500.
To see that that was just an accident - it's not necessary for having things
work - replace x1, x2, y1 and y2 in line 135 by -1, 1, -1 and 1 respectively.
Run the program.  Now the on-screen "graph paper" only extends from -1 to 1
in each of x and y.

     Some people find this graphics screen glaring.  Change the number 15 in
line 125 to a 7, and run the program again.  Color number 7 is a light grey.

     Line 510 is very important.  If you look through lines 520-580 you'll
see that the only variable *GRFPPR uses (besides those in its "calling
sequence" - the list of variables following the subroutine's name in line 500)
are C, X and Y.  Line 510 says (commands) that these variables are "local".
That means they act only inside the subroutine and do not interact with the
main routine.  There can be a variable X in the main routine too; if the X in
the main routine has, say, the value 5.23 when the subroutine is called, and
the subroutine gives its X some other value, the X in the main routine is
unaffected; its value remains 5.23.  (All the variables in the calling
sequence are automatically local, and shouldn't be declared as local.)

     Local variables are a valuable feature.  Because of them subroutines can
be written without worrying about conflicts between the variables in the
subroutine and those in a main routine that will use the subroutine.  So an
activity that a programmer may wish to use in several main routines - such as
drawing graph paper - may be written as a subroutine, filed away, and later
used in other programs.

     Let's file away *GRFPPR.  First we have to get it by itself.  List DEMO3
and then type in
                       delete 1-499
List the program again, to see that the subroutine is all you now have.
Now key F6;
                       save "
appears on the screen.  Type in
                       grfppr
(followed by the Enter key).  To see that you now have it saved on your disk,
key F1 and then Enter and you will see a list of all the .UB files that you
have.  One of them should be GRFPPR.UB - UBASIC's "save" instruction
automatically added the ".UB" extender to the name that you gave the file.
That extender means that the files contents are a UBASIC program.

     Reload DEMO3 and we'll continue exploring *GRFPPR.  The variable C is
used 4 times, in lines 550-580, to set the colors of the coordinate lines in
the graph paper.  The axes' colors are set in lines 530-540 to color number
1, which is deep blue.   Color number 3 is light green, as you can see by
running the program.  Experiment with different values for C.

     It's pretty clear what lines 530 and 540 do.  Line 550 draws all the
vertical (x=constant) coordinate lines to the left of the y-axis.
It consists of 5 instructions put together on one line. They are:
                       x= -xtick
                       while x>=x1
                         line (x,y1)-(x,y2),c
                         x=x-xtick
                       wend
Lines 2 to 5 here constitue a loop:  the instructions between the "while"
line and the "wend" line are to be carried out repeatedly for as long as the
condition specified in the while line ( x>=x1 ) holds.  ("Wend" just means
"end of 'while' loop".)  The value of X is changed each time lines 3 and 4
are executed; it's lowered by the amount xtick.  Eventually X will become
less than X1, the loop will stop, and program execution will proceed to the
next program line, line 560.  Why did line 550 start with
                       x=-xtick  ?
Well that's the value of x for the first vertical coordinate line to the left
of the x-axis.

     Line 560 draws the vertical coordinate lines to the right of the x-axis.
Lines 570 and 580 similarly draw the horizontal coordinate lines.

     Finally line 590 gives the "return" instruction that must be used to say
that the subroutine's work is done and execution should continue back in the
main program, at the point right after the instruction that called the
subroutine.  (The UB system remembers where that is.)

     Let's write another subroutine - one that plots a function.  One of the
variables in its calling sequence will stand for the name of the function
that is to be plotted.  UB allows you to do that.  So we'll be able to use
the subroutine to plot several different functions in a single program run
(in different colors, perhaps).

     We need to plan.  What will the subroutine need to know?
                 the name of the function
                 the x-range for which it's to be plotted
                 the color to use for the curve.
Also, because of how UB draws curves (see lines 140-210 of DEMO3) the
subroutine should be told the spacing of the X values to be used in plotting
the function.

     We start by entering
                       new
and then F4 to be sure there's no program left in the editing activity.  Then
we type in
                       500  *FUNCPLOT (&fnF(),x1,x2,xstep,c)    .
That strange looking first item in the calling sequence is a function-name
variable.  The ampersand, "fn", and the parentheses are all required.  Type
in (being careful to indent the lines that are shown indented)
                       510  local x
                       520  x=x1:pset(x,fnf(x)),c
                       530  while x<=x2-xstep
                       540    x=x+xstep
                       550    line-(x,fnf(x)),c
                       560  wend
                       570  return

     List the program.  The indentations have disappeared!  They can be
restored - and this time they'll be permanent - as follows:  Modify line 540
in the listing on the screen, by inserting the desired spaces.  I.e., use
arrow keys to place the cursor on line 540, between the number 540 and the
first x;  press the Insert key and then press the space bar 2 or 3 times to
insert the number of spaces you wish; and then press Enter.  Do the same to
line 550.  Now list the program again, and you'll see the spaces are there.
It's a slightly annoying feature of UBASIC that indenting lines must be done
this way.

     Will this function work?  Hoping for the best, let's file it.  Key F6,
then
                       subplot
and then Enter.  It's saved as file SUBPLOT.UB.  Now let's try it out.
Add lines
                       200 screen 23
                       210  view (0,0)-(639,479),7
                       220  window (-7,2)-(7,-2)
                       230  '
to set up our graphics screen,
                       400  fnf1(x)
                       410  return (4/#pi)*cos(#pi*x/2)
                       420  '
to define the function we wish to plot, and
                       300  gosub *FUNCPLOT(&fnF1(),-6,6,0.1,4)
                       310  end
                       320  '
to call the subroutine.

     (About line 410:  "#pi" is, guess what, the number pi.  "cos" is the
cosine function - working on radians, not degrees.)

     List the program and proofread it.  Save it as DEMO4.  Run it.  Color 4
turns out to be red.

     It would be nice to have graph paper.  List the program and key F8,
followed by
                       grfppr
followed by the Enter key.  List the program now.  Subroutine *GRFPPR has been
added on, with new line numbers!  That's what the "append" command (invoked
by F8) does.  Add the program line
                       290  gosub*GRFPPR(-10,10,1,-2,2,0.1)
and then run the program.  Neat, eh?  Save it as DEMO4 again.

     Let's add in a second function:
                       430  fnf2(x)
                       440  local a,c1,c2,f
                       450  a=4/#pi
                       460  c1=cos(#pi*x/2): c2=cos(3*#pi*x/2)
                       470  f=a*(c1-c2/3)
                       480  return(f)
and change line 310 to
                       310  gosub *FUNCPLOT(&fnF2(),-6,6,0.1,1)
and add
                       320  END
                       330  '    .
Also add
                       580  '
for neatness.  Check the listing of the program, and run it.

     Lines 430-480 make up a multi-line function definition.  That's allowed.
"local" works in function subprograms, just as in subroutines.

     We'll add a third function.  But we don't have space for it. So we'll
renumber the lines from 500 on, to start from 1000.  Type in
                       renum 1000,500
(after returning to the editing screen) and list the program to see that all's
well.  Now add in
                       490  '
                       500  fnf3(x)
                       510  local sum,termsign,i,term
                       520  sum=0: termsign=1
                       530  for i=1 to 8
                       540  term=(termsign/(2*i-1))*cos((2*i-1)*#pi*x/2)
                       550  sum=sum+term
                       560  termsign=-termsign
                       570  next i
                       580  return ((4/#pi)*sum)
                       590  '
and
                       315  gosub *FUNCPLOT(&fnf3(),-6,6,0.1,0) .
Check what you've typed in, save the program, and run it.  (Electrical
engineering students may find these graphs familiar.)

     So we can put loops inside function definitions!  Lines 520-570
calculate a sum of 8 terms of a (Fourier) series.  The sum is "initialized"
as zero (line 520), the terms are calculated one by one (line 540), and put
into the sum (line 550).  The business with termsign is because the terms
have plus and minus signs alternatingly (line 560).

     The ability to put a function-name variable in the calling sequence of a
subroutine adds considerable power to the subroutine construct.  It can also
be done with functions - a function-name variable can be one of the variables
in the variable-list of a function.  So we can define and use functionals!
(At least to some degree.)  There is an example of this, a numerical-
integration functional, in "lesson 9" in the UB manual.  It can be seen via
UB's on-line help system, which will be introduced in our next lesson, or by
printing out the manual as I'll describe in Appendix IB.

     Note the difference in the forms of our 2 kinds of subprograms:
Subroutines start with an asterisk, functions with the letters fn.
Subroutines are called by a gosub instruction, functions are invoked by name
in the middle of instruction lines just like the names of built-in functions
such as cos and sqrt.  The return instruction at the close of a function
subprogram specifies the value of the function, while that at the close of a
subroutine is blank.

     If we hadn't made function plotting into a subroutine we would have had
to, in our last version of DEMO4, write most of the lines that are now in
*FUNCPLOT three separate times - once for each function plotted.  That tells
you one of the purposes of subroutines: if you want to do something
moderately complicated several times in one program, you needn't write the
instructions for it several times; you can put them into a subroutine and
call it whenever it's needed.

     Subroutines also help make a program somewhat intelligible.  In DEMO4
the main routine ends at line 330 and contains altogether 6 instructions.
Once you know what "view" and "window" do, it's almost readable.  The 5
subprograms that make up the rest of the program can be figured out
individually.

     The subroutines we've used up to here have not sent any data back to the
main program (they've just drawn things on the screen).  But subroutines can
do that, as we'll see; and they can do more of it than function subprograms
do.  But first let's play a bit:
     1.  Change the 7's in line 220 of DEMO4 to 4's, and run the program.
         You can see more clearly what fnF3 is like.  But it looks jagged.
         Is that really the way the function is, or is it because the
         plotting was done too coarsely?  Change the number 0.1 (the x-step)
         in line 315 to 0.01, by inserting a zero.  Run the program again.
         What if you change the 8 in line 530?  To 4?  To 2?  To 20?
     2.  Change DEMO4 (But still keep the original DEMO4 saved, on your disk)
         to plot the two functions
                 f1(x)=sqrt(1-x*x) and f2(x)=-sqrt(1-x*x)
         for x between -1 and 1.  Change the "window" settings, if you wish.
     3.  Try the three functions
                 cos(2 arccos x), cos(4 arccos x), cos(6 arccos x)
         (Remember that in UB these are written  cos(2*acos(x)), etc.)
     4.  Reload the original DEMO4, add an identifying line at the head of
         the program, and save the program.


Features learnt in this lesson:
     subroutines, gosub, *, return, calling sequence
     local variables
     colors 7, 3 and 4
     delete
     while/wend loops
     use of function-name variables in a subroutine's calling sequence
     append
     more about function subprograms
     Lesson 4:  Arrays, mostly:

     But first let's do a little fun stuff.  You've been teased long enough
seeing UB's colors one at a time; let's see them all.  We'll use an additional
feature of the "line" instruction: it can also draw rectangles, and color them
in.  To see this, go into UB and type in the following program:
                        10  'DEMO5
                        20  '
                       100  screen 23
                       110  view (0,0)-(639,479),0
                       120  x1=0: x2=1: y1=0: y2=1
                       130  window (x1,y2)-(x2,-y1)
                       140  '
                       150  line (0.3,0.3)-(0.6,0.6),15,"bf",4
And save and then run it.  The "bf" stuff between the last two commas on line
150 (the quotation marks are an essential part of the instruction!) made the
instruction draw a box instead of a line (that's the "b") and fill it with
color (that's the "f").

     How do you find out about such things - if they're not taught in this
introduction?  Well UB comes with an informal manual that I'll describe in
Appendix IB; and you can view the manual while working in UB, through UB's
on-line help system.  To do the latter, you must first activate the help
system, as I'll now describe: (This description comes from the file
UBHELP.DOC, which was formed when you installed UBASIC.  It's a text file, and
can be viewed - from DOS, not from within UB - by issuing the DOS instruction
                       type ubhelp.doc ).

     Make sure you've saved DEMO5, and exit from UB.  At the DOS prompt, type
in "ubhelp/d" followed - without any spaces - by the name of the disk drive
and directory that your UBASIC is installed in.  I, for example, type in
                       ubhelp/dc:\ub884
since I keep UB in the directory \UB884 on my C: drive.  Then type in
                       ubibm32
to start UB; and on-line help is available.  Use it to find out about the
"line" instruction, as follows:  Key  Ctrl-\ (hold down the Ctrl key and press
the backslash key).  A box will appear, containing various topic headings and
UB instruction words - but not "line" because it's farther along
alphabetically.  Key Page Down twice to get "line" on the screen and then use
arrow keys to highlight it; then key Enter.  You'll see an explanation of the
"line" instruction.  When you've absorbed it, key Home to get back to UB's
main (writing and editing) screen.  Reload DEMO5.

     (What have you done?  Where are the help texts?  Resident in memory (RAM)
somewhere.  When you finish working with UB and you exit from it, they WON'T
be removed automatically!  They'll sit around taking up room in memory.  You
have to remove them manually.  Entering
                       ubhelp/r
at the DOS prompt, after you exit UB, will do that.  A pain to remember.
Later in this lesson we'll make it automatic.)

     Well, DEMO5 is still showing just one color.  So replace line 150 by this:
                      150  for i=0 to 15
                      160  x1=(0.3+6.25*I)/100: x2=x1+0.0525: y1=0.05: y2=0.95
                      170  line (x1,y1)-(x2,y2),15,"bf",i
                      200  next i
                      210  end
Save the program and then run it.  You see all 16 colors.

     To make the display more informative, add the following line
                       180  locate 5*i,30: print i;
and change the number 479 in line 110 to 460.

     "locate"?  Try help.  What coordinates is it using?  Character spaces for
x, and line spaces for y, apparently.

     460?  0.3?  6.25?  0.0525?  Where did those come from?  From
experimenting.

     So you see UB's 16 colors.  Observe that the first 8 are darkened
versions of the second 8.

     In fact there are other colors available in UB.  But UB can only show 16
colors at any one time, and the 16 that you see constitute the default
"palette".  The palette can be changed, using the "color=" instruction.  I
won't go into that.

     [An exercise: Making a "kaleidoscope".  Delete lines 150-210 of DEMO5,
and change the name of the program to DEMO6. Change the x and y ranges in line
120 to go from -1 to 1 instead of 0 to 1; that makes it easier to arrange for
symmetry.  Now put in instructions to draw a "random" colored rectangle - for
example:
                       150  x1=rnd: x2=rnd: y1=rnd: y2=rnd: c=int(16*rnd)
                       160  line (x1,y1)-(x2,y2),15,"bf",c
"Rnd" is a UB function.  It produces a pseudo-random number between 0 and 1,
and it produces a new one each time it is used in a UB program.  So in the
fifth instruction on line 150, 16*rnd is a (pseudo-)random number between 0
and 16; and its integer part ("int" is UB's integer-part function) is a
random integer from 0 to 15, which is used in line 160 as a color number.

     Let's get more rectangles by adding the line
                       170  goto 140
That will make the program into an infinite loop!  So recall how to get out of
one, and then run the program.  Things are changing too fast to see clearly!
Use the Pause key to halt execution of the program.  Lots of rectangles on
screen, but no symmetry.  Press any key to resume execution of the program.
Stop it, and list it.

     We have two problems: how to slow the program, and how to introduce
symmetry.  There's a "pause" instruction in UB that solves the first problem.
It doesn't cause a halt, as the Pause key does; just a pause.  Add the line
                          168 pause 2
and save and run DEMO6.  "pause 2" causes a pause of about 2/10 of a second;
similarly with any other positive integer.

     Symmetry.  Add the line
                       162  line(-x1,y1)-(-x2,y2),15,"bf",c
and run the program.  Now you have some symmetry, and you're covering half the
screen instead of only a quarter.  Figurte out how to get symmetry about the
x-axis too, and do it.  You should get a pretty neat display.

     It would be nice to have a sort of 8-way symmetry by adding symmetry
about the lines y=x and y=-x.  Can you see how to do it?

     (A program much like this, running on Apple II's in computer-store
windows, sold an awful lot of Apple computers in the 70's, when personal
computers were just getting going.)

     On to arrays!  An array is just a collection of objects arranged in some
order. We shall deal only with arrays of numbers; linear arrays such as
           (-1,2,5)   or   3
                           1
                           7
and rectangular arrays such as
                   1   7
                  -2   4
                   3  -1
UBASIC also allows for 3-dimensional arrays, but we won't consider those.

     How does UB keep track of where each number is in an array?  By the use
of "subscripted variables" - but since there is no provision for actually
typing subscripts, they are shown as follows: If we choose to call the array
(-1,2,5) "A", for example, then the three numbers in that array will be
denoted "A(1)", "A(2)" and "A(3)" respectively.  The numbers inside the
parentheses thus serve as subscripts; "A(3)" means "the third number in the
array A", which is 5.  For 2-dimensional arrays we use two subscripts to
locate each component of the array: If B is the rectangular array above, then
"B(1,2)" denotes the number in the first row and second column of that array,
so that B(1,2) is 7.  The row-number is always the first subscript and column
number the second.

     Mathematicians have defined algebraic operations involving arrays -
"addition" of an array to an array, various forms of "multiplication" of an
array by an array - and in the context of such operations, linear and
rectangular arrays are called "matrices" (singular: matrix), and linear arrays
are also called "vectors".  One of these operations is the "inner product" of
two vectors, which is defined as follows: Suppose we have two vectors A and B,
of the same dimensionality - that is, they have the same number of components.
For example
                 A = (-1,2,5)  and   B = (3,sqrt(2),14)
are both of dimension 3.  The inner product (also called "dot product", or
"scalar product") is a number that is obtained by multiplying the first
component of A by the first component of B, multiplying the second component
of A by the second component of B, etc; and adding up all of those products.
Thus in our example
           A*B = (-1*3) + (2*sqrt(2)) + (5*14) = 69.828  .

     Let's do that calculation on the computer.  We have to write a program
that sets up the arrays A and B and then calculates their inner product.  Type
in the following:
                        10  'DEMO7    (the date)
                        20  '
                        30  A(1)=-1: A(2)=2: A(3)=5
                        40  B(1)=3: B(2)=sqrt(2): B(3)=14
                        50  inprod=0
                        60  for i=1 to 3
                        70     inprod=inprod+A(i)*B(i)
                        80  next i
                        90  ? inprod
                       100  end

     Lines 50-80 form the inner product.  Line 50 "initializes" it as zero and
line 70 multiplies each component of A, in turn, by the corresponding
component of B and adds the result into Inprod.  The work of these four lines
could have been accomplished by one line:
                       inprod=A(1)*B(1)+A(2)*B(2)+A(3)*B(3),
but that line is perhaps more tedious to type than lines 50-80.  A more
important reason for doing it the way we did is that lines 50-80 can be very
simply modified (as we shall do below) to handle vectors of any
dimensionality, not just vectors with 3 components.

     Save the program, and run it.  It doesn't run - we get an error message
referring to line 30.  The error turns out to be that we've not done something
that UB requires: every array variable (such as A() in line 30) must be
"declared" before being used.  We must explicitly say that A and B are array
variables, and also give their dimensionalities.  The way to do that is by a
"dim" instruction.  Add the line
                       25  dim A(3),B(3)
to the program.  Save and run.  It works.

     Really, getting A*B by calculator is a lot faster in this case.  But the
program can be generalized simply, to cover cases that are not so quickly done
on a calculator.  Before doing that, let's replace lines 30 and 40 by
something that is less tedious to type and that can be easily generalized.
Type in the following lines:
                       30  for i=1 to 3: read A(i): next i
                       35  data -1,2,5
These lines replace the old line 30.  The new instructions "read" and "data"
work together: When i=1 on line 30, and the active instruction is
read A(1), the UB system looks for a "data" statement in the program and finds
the first item in that data list.  That item is the number -1, and UB sets
A(1) equal to -1.  UB also marks the item -1 as already read.  The next time
around the loop in line 30, i is 2 and the active instruction is  read A(2).
Again UB looks for the data statement, finds it, picks up the first data item
that was not already read - that's the number 2 - and sets A(2) equal to it;
and marks off that data item.  Etc.  Run the program to see that the result,
the value of inprod, is the same as before.

     Now type in (or change lines 30 and 35 into)
                       40  for i=1 to 3: read B(i): next i
                       45  data 3,sqrt(2),14
and run the program.  Fine.

     Now let's generalize the program to handle vectors of dimensionality n
(in the present case, n=3).  Add the line
                       22  n=3
and change the 3's in lines 25, 30, 40 and 60 to n's.  Save and run the
program.  Fine.

     Let's try another pair of vectors:
                       A=(1,2,3,4,5) and B=(1,1,1,1,1).
Change the 3 in line 22 to 5, and change data statements 35 and 45
appropriately.  The program's output should now be the number 15.

     Up to now we've defined vectors by either directly assigning values to
their components, one by one, or via read and data statements.  But sometimes
the component values may be given by formulas.  Let's try that: Replace "read
A(i)" in line 30 by "A(i)=i", and "read B(i)" in line 40 by "B(i)=1".  That
should give us the same A and B as we just had.  Run the program; the output
should again be "15".

     At this point the data instructions are not being used at all.  So erase
lines 35 and 45, and list, save, and run DEMO7.  15 again.  Fine.

     Change the value of N, in line 22, to 100.  Run the program.  5,050.
Faster than little Gauss got it, but using less intelligence.

     Change "B(i)=1" in line 40, to "B(i)=i".  What should you get when you
run the program?

     Change the "100" in line 22, to "200", and run the program.  It doesn't
run!

     "Variable area full. in 25"?  Let's see; the declaration in line 25 now
tells the UB system to reserve space for 2 vectors, each containing 200
numbers.  That's 400 numbers altogether.  Your computer probably has several
million bytes of RAM.  Why has UB run out of space?

     Well, to begin with, UB doesn't know about all those millions of bytes.
UBASIC 8.84 is still an old fashioned DOS program and it works primarily in
the first 640K bytes of memory.  (It does have a way of handling more RAM,
through its EMA instructions; I won't go into that here.)  When you're working
in UB, the UB interpreter takes up some of those 640K bytes, and there's some
overhead for each array in RAM.  Still that leaves perhaps 400,000 or so bytes
for storing variables.  How can 400 numbers overflow that?

     The answer is that UB reserves a lot of space - over 1,000 bytes - for
each number.  That's because it allows each number to have some 2,600 digits.
So line 25 asked for more than 400,000 bytes, and there weren't that many
available.

     There's a way out of this.  The amount of space alloted to each number
can be specified by using UB's "word" instructions.  The over 1,000 bytes -
more accurately, 542 2-byte words - is only a default, in the absence of a
"word" instruction.  If we add the line
                       21  word 5
to our program, it runs perfectly well.

     "word 5" sets the space for each variable at 5 2-byte words, or 10 bytes.
That is enough space for about 24 digits, decimal.  (UB works internally in
base 2.)  For our present calculation, "word 2" is also sufficient.

     UB represents real numbers (and real and imaginary parts of complex
numbers) in a fixed-point form.  That is, it allows a certain number of bytes
for the digits to the right of the decimal point, and a certain number for the
digits to the left.  It does not use "floating decimal" or "scientific"
notation.  Its default is 4 words or 8 bytes for the digits to the right
(enough for 19 decimal digits) and 538 words or 1076 bytes for the digits to
the left of the decimal point.  (It is different for complex numbers.)  To
depart from the default, the "point" instruction will reset the space
allocated for the part of the number to the right of the decimal point (as
discussed in Lesson 1.), and the "word" instruction will reset the total space
allocated for the number.  Word 2 worked in DEMO7 because all the numbers
involved in the program are integers.  If we change "B(I)=I" in line 40 to
"B(I)=sqrt(I)" and run DEMO7, we get an "overflow" message, because we've
tried to use 4 words for the decimal part of a number while using only 2 for
the number altogether.  If we change line 21 to  read
                       21  word 4: point 2   ,
DEMO7 will run correctly, using the least possible memory space for each
number.  ("point 1" is illegal, as is "word 1".)  It is rarely necessary to be
so stingy.  (You can learn more about this from the manual, or the help
system.  Look under the headings "numbers" and "variables".)

     For rectangular arrays - matrices - the operation we'll look at is matrix
multiplication.  If A and B are matrices - for example
                 A =   2  1  5       ,  B =   3  1
                      -2  0  7                2  2
                                              1  3
- the product AB is defined only when the dimensionality of the rows in the
left factor is equal to the dimensionality of the columns in the right
factor.  In the present example that is so: the dimensionality of each row of
A (regarded as a vector) is 3, and the dimensionality of each column of B
(regarded as a vector) is also 3.  Then the product AB is also a matrix, whose
(i,j)-entry (the number in the i'th row and j'th column of AB) is defined to
be the inner product of the i'th row of A with the j'th column of B.  So in
our example the (2,1)-entry of AB is the inner product of (-2,0,7) and 3 , or
                                                                       2
                                                                       1
-2*3 + 0*2 + 7*1 , which is 1.  In fact

                 AB =  7  24
                       1  19 .

(It is not the same size, in this case, as either A or B.)

     We shall write a program to calculate matrix products.  It will naturally
use our program for calculating inner products, so for convenience we'll
convert DEMO7 into a function subprogram.

     Let's first renumber DEMO7, by simply giving the command "renum".  It
should now read:
                        10  'DEMO7
                        20  '
                        30  word 4:point 2
                        40  N=200
                        50  dim A(N),B(N)
                        60  for I=1 to N:A(I)=I:next I
                        70  for I=1 to N:B(I)=sqrt(I):next I
                        80  Inprod=0
                        90  for I=1 to N
                       100    Inprod=Inprod+A(I)*B(I)
                       110  next I
                       120  print inprod
                       130  end
The inputs to our function will be the vectors whose inner product is wanted,
so the function will not need to construct the vectors itself; so we should
erase lines 60 and 70.  We should also erase lines 120 and 130.  The word and
point values will be set by the program that uses our function, and they must
not be reset in the middle of a run; so we erase line 30.  Also line 40, since
that information should also be supplied by the main program.  Line 50 also
shouldn't be in the subprogram; the dimensioning will have been done in the
main program.  Change line 10 to the function declaration
                        10  fninprod(n,&A(),&B())
and change line 20 to
                        20  local inprod,i
and add the line
                       120  return(inprod)
and we are done.  We may renum the program, for neatness.

     There's some strange syntax here, on line 10.  Before explaining it,
let's add a "driver" to see whether the function works.  Type in
                         2  n=3
                         4  dim c(n),d(n)
                         6  for i=1 to n: c(i)=i: d(i)=i: next i
                         8  ? fninprod(n,&c(),&d())
                         9  end
and save and run the program.  The output is "14", which is right.  Strip off
the driver ("delete 2-9"), list and save the program - say as FNINPROD.UB .

     About the form of line 10: The parentheses following A and B inform UB
that A and B are arrays; they must be present.  The ampersands preceding A and
B are not absolutely necessary but they accomplish something.  Without them,
duplicate copies of the vectors A and B would be made in RAM and used by the
subprogram - so the ampersands economize on memory use.  (This is a matter of
what computer scientists call "call by name" or "call by reference", as
against "call by value".  There's something in the help system about it, under
the heading "SUBROUTINE".)  Finally, in addition to the obvious function
arguments A and B, we need the argument N to tell the subprogram what the
actual dimensions of the vectors are.  The subprogram can't find that out for
itself by looking at A and B.

     Next lesson we'll write the matrix - multiplication routine.  To end this
lesson I'll describe a way to make activating the help system, and clearing it
out of memory at a session's end, automatic.

     It can be done via a "batch file" - a list of DOS commands that can be
activated by typing in the file's name, on the DOS command line.  Exit from UB
and go back to the DOS root file, \.  Enter the command
                       edit ub.bat
and you'll find yourself in DOS's  text editor, "Edit".  Write the following:
                       cd\ub884
                       ubhelp/dc:\ub884
                       ubibm32
                       ubhelp/r
(This is on the assumption that you have UBASIC in the subdirectory \UB884, in
drive C:.  If the situation is otherwise, replace "\ub884" by the correct
subdirectory name, in the first 2 lines; and replace C on the second line by
the correct drive letter.)  The 4 lines of this batch file will do the
following: send the DOS control to the subdirectory that UB is in; activate
UB's help facility; start UB; and, when you exit UB, remove the help data from
RAM.  When you've finish writing UB.BAT, exit from Edit by keying Alt, then f,
then x.  You will be asked whether you wish to save this file.  Respond
affirmatively, by keying Enter.  Once this is done you can start a UBASIC
session by simply typing in
                       ub
at the DOS prompt, and the four commands in this batch file will be carried
out.


Features learnt in this lesson:
     on-line help
     the 16 colors
     int
     notation for arrays
     dim
     read and data
     word
     syntax for passing arrays to a subprogram
     a batch file for activating and removing help
    Lesson 5:  More about arrays.  Plotting functions of a complex variable:

     Let's set up the two matrices

                                                 3  1
                 A =    2  1  5      and   B =   2  2
                       -2  0  7                  1  3

in a program, to use for multiplication.  Specifying the position of a number
in a rectangular array requires two subscripts - one for the row and one for
the columns.  So for example A(1,1) is 2,  B(3,2)is 3.  The natural way to
handle this is by a loop inside a loop, as in:
                       100  for i= to 2
                       110    for j=1 to 3
                       120      read A(i,j)
                       130    next j
                       140  next i
                       150  data
In what order should we put the matrix entries, in line 150?  Reading the data
is done by 2 nested loops: the inner loop in lines 110-130 and the outer loop
specified in lines 100 and 140.  The outer loop sets i equal to 1 initially,
and the inner loop takes over and reads A(1,1), A(1,2) and A(1,3) - the first
row of the matrix A.  Then the outer loop sets i equal to 2 and the inner loop
reads the second row of A.  So line 150 should be
                       150  data 2,1,5,-2,0,7   .

     We can display the matrix, via print instructions, to see that we have it
right.  That can be done neatly, if a bit mysteriously, as follows:
                       160  '
                       170  for i=1 to 2
                       180    for j=1 to 3
                       190      print A(i,j);
                       200    next j
                       210    print
                       220  next i
Try it - but first add on the line
                        50  dim a(2,3)
to "declare" the array A to UB.  Let's name the program DEMO8 - add the line
                        10  'DEMO8    (date)
and save and run the program.  Neat output.

     The semicolon at the end of line 190, and line 210, make use of some
helpful features of the print instruction in order to give a natural-looking
format to our data.  A print instruction that ends without a punctuation mark,
like line 210 here and like all our previous print instructions, has the
meaning that whatever is being printed by that instruction completes a line of
text - there is an implicit "carriage return" in the instruction.  But a print
instruction that ends with either a comma or a semicolon (those are the only
punctuation marks that work here) does not imply a carriage return, so the
next print instruction afterward continues to print on the same line.  So line
190, in the inner loop, causes A(i,1), A(i,2) and A(i,3) to be printed on a
single line.  And line 210 says, in effect, "proceed to the next line for
any further printing".

     (The indentations of the program lines, that I have shown above, are
particularly helpful for reading nested loops.  Recall, from Lesson 3, how to
indent lines.)

     Now let's set up B.  Delete lines 170-220 and write, for B, instructions
like those in lines 100-150:
                       170  for i=1 to 3
                       180    for j=1 to 2
                       190      read B(i,j)
                       200    next j
                       210  next i
                       220  data 3,1,2,2,1,3
Note that here i runs from 1 to 3 and j from 1 to 2, since B has 3 rows and 2
columns.  Add ",B(3,2)" to line 50.

     We'll call the product "C".  C=AB.  What are the dimensions of C?  In
general, if A is a k(row)-by-l(column) matrix, and B is an l-by-m matrix, then
AB is a k-by-m matrix.  So C will be 2-by-2, and you must declare it so on
line 50.  Since
                       C(i,l)= the inner product of the i'th row of A
                                  with the j'th column of B
we can use fnInprod to do all the calculation.  For that we must
     1.  Pick out the i'th row of A and make it a vector
     2.  Pick out the j'th column of B and make it a vector
     3.  Get the inner product of those two vectors and assign it to C(i,j).
This will do it:
                       230  '
                       240  for i=1 to 2
                       250    for j=1 to 2
                       260      for r=1 to 3
                       270        V1(r)=A(i,r)
                       280        V2(r)=B(r,j)
                       290      next r
                       300      C(i,j)=fnInprod(3,&V1(),&V2())
                       310    next j
                       320  next i
                       330  end
Of course you need to declare V1 and V2 - on line 50, or on another line.  And
we need to append fnInprod, to let line 300 work,  Do all that, and save and
run the program to see whether it will run or produce an error message.  The
program has no output!  (If it does not run, check for mistakes in typing, and
correct them.)

     Study lines 260-290 above, until you see what they're doing.  Why does r
range from 1 to 3?

     To check that C has been calculated correctly, figure out yourself that
C(2,2), for example, is 19; and see whether DEMO8 has calculated it correctly
by typing in
                       ?C(2,2)
in immediate mode.

     To see some points of syntax, let us make this program into a general
matrix-multiplying subroutine.  We'll call the subroutine *MATPROD.  Its
operation will simply be:  given two matrices A and B that can be multiplied,
it will produce the product AB.  It will also need to be given the dimensions
of the matrices A and B, just as fnInprod needed to be told the dimensions of
its input vectors.  So let's suppose that A is a k-by-l matrix, and B is an
l-by-m matrix.  Replace line 10 by
                        10  *MATPROD(K,L,M,&A(),&B(),&C())   .
Note that although A, B and C (C will be the output matrix AB) are rectangular
rather than linear arrays, the syntax for mentioning them in the calling
sequence is the same as that for linear arrays.

     This is our first subroutine that has an output - the matrix C - that the
main routine may use.  So it is worth mentioning that unlike the ampersands on
A and B, that are optional in the calling sequence and serve only to economize
on memory, the ampersand on C is necessary; without it the main routine would
not be able to find C.

     The subroutine will not have to generate A and B, so we can (and must)
delete lines 100-150 and 170-220.  We can also delete line 160, change the
"end" in line 330 to "return" and for neatness add the line
                       340  '   .
Make the index I in line 240 run from 1 to K, make the J in line 250 run from
1 to M, and make the R in line 260 run from 1 to L.  We make all the variables
that are internal to the subroutine, local - so type in
                        20  local i,j,r,V1,V2   .
As for the dimensioning in line 50: the program that calls this subroutine
will have dimensioned A,B and C, so those arrays must not be dimensioned again
inside the subroutine.  But the subroutine's local arrays V1 and V2 must be
dimensioned.  So type in
                        50  dim V1(l),V2(l)   .
Oh - the "3" in the variable list of fnInprod, on line 300, should be changed
to an "l".  Let's also add a little bit of internal documentation:
                        12  'Calculates the product C=AB.
                        14  '  A is a k-by-l matrix and B is l-by-m.
                        16  '

     Did we write the subroutine correctly - will it do what we wish?  To find
this out we must call on a temporary "driver" - a main routine that will use
the subroutine and show us the result.  But first list the program and check
it for typographical errors.  Then enter
                       renum 300,10
to give us space for the driver, and save the program.  A simple driver is:
                        10 'DEMO8
                        20  word 3: point 2
                        30  k=3: l=4: m=5
                        40  for i=1 to k
                        50    for j=1 to l
                        60      C(i,j)=i+j
                        70    next j
                        80  next i
                        90  for i=1 to m
                       100    for j=1 to m
                       110      D(i,j)=1
                       120    next j
                       130  next i
                       140  gosub *MATPROD(K,L,M,&C(),&D(),&E())
                       150  for i=1 to k
                       160    for j=1 to m
                       170      print E(i,j);
                       180    next j
                       190    print
                       200  next i
                       210  end
                       230  '
Save and run the program.  It doesn't run!  I forgot to dimension the
matrices.  So add
                        35  dim c(k,l),d(l,m),e(k,m)   .
Now the program runs!  Figure out what the matrices C and D are, and what E
should be.  Is the displayed E correct?  (It should be.)  Save the corrected
DEMO8.

     I'll end this introduction to UBASIC with a bit of fun that may turn out
useful.  We'll get some pretty pictures, from a program for graphing functions
of a complex variable.  Along the way you'll learn something of UB's handling
of complex numbers.

     We can't, of course, fully plot a function w=f(z) in the way we plot a
function of a single real variable.  It would require 4 real space dimensions.
What we shall do is specify a curve in the z-plane and show it and its image
in the w-plane and the connections between the z and w values. We'll do that
by choosing N+1 points z(0), z(1), z(2),...,z(N) on the z-curve, and
calculating the corresponding w values.  Superimposing the w-plane on the
z-plane, we'll mark these z and w values and draw a line from each z to its w.
UB works naturally with complex numbers just as with real numbers, and its
elementary functions work for complex values of their arguments, so this will
be fairly easy.  Let's start with
                       100  'DEMO9    (date)
                       110  '
                       200  screen 23
                       210  view (0,0)-(639,479),15
                       220  x1=-3: x2=3: y1=0.75*x1: y2=0.75*x2
                       230  window (x1,y2)-(x2,y1)
                       240  goto 340
                       250  '
                       300  fnf(z)  'the function that will be plotted
                       310  local w
                       320    w=exp(z)
                       330  return(w)
                       340  '
                       350  n=50
                       360  dim z(n)
                       370  '
                       400  'Specifying the curve in the z-plane:
                       410  zc=0: R=1
                       420  gosub *CIRCLE(Zc,R,N,&Z())
                       430  z1=-#pi+1.25*#i: z2=z1+2*#pi
                       440  'gosub *LINE(z1,z2,N,&z())
                       450  '

     The subroutines *CIRCLE and *LINE will generate the points on the
selected countour - a circle with center zc and radius r in the case of
*CIRCLE, and a line segment with endpoints z1 and z2 in the case of *LINE.
I've "rem'd out" line 440 - deactivated it by making it a remark - so we'll be
using a circle, initially.  The symbol "#i" on line 430 is UB's notation for
the complex unit i.  Before going on with the main program, I'll write the
subroutines, giving them line numbers that will place them after the main
program.

                     1000  *CIRCLE(zc,r,n,&z())
                     1010  local k
                     1020  for k=0 to N
                     1030  z(k)=zc+R*exp(2*#pi*#i*k(N)
                     1040  next k
                     1050  return
                     1060  '

     Note that in the array (list, vector) of z-values generated by *CIRCLE,
there is one with subscript zero.  That is allowed in UBASIC, and space for it
is automatically set aside by line 360.  Line 1030 specifies that the z-points
are equally spaced around the circle, and in fact z(0) will be the same as
z(1), so that z(0) is superfluous here.  But it does no harm, and in *LINE
it's needed.
                     1070  *LINE(z1,z2,n,&z())
                     1080  local k
                     1090  for k=0 to n
                     1100    z(k)=z1+(z2-z1)*k/n
                     1110  next k
                     1120  return

     Now let's complete the main program:
                       500  radz=(x2-x1)/200: radw=radz 'radii of circles that
                       505  '                  will mark the z and w points.
                       510  for k=0 to n
                       520  z=z(k): w=fnf(z)
                       530  circle(re(z),im(z)),radz,0
                       540  circle(re(w),im(w)),radw,9
                       550  line(re(z),im(z))-(re(w),im(w)),9
                       560  next k
                       570  end
                       580  '

     "Circle", in lines 530 and 540, is not the subroutine you just typed in,
but a UB instruction.  To see its syntax, use the on-line help.  "Re(z)" and
"im(z)" are the real and imaginary parts of z.

     Save and run DEMO9.  It should work.

     Line 240 is necessary.  Without it, program execution would come to line
300 and halt there, as line 300 does not contain an instruction that is to be
executed at run time.  Try remming out line 240, temporarily, and seeing what
happens when the program is run.

     The colors specified in lines 530-550 are of course matters of choice.
So is the value of N in line 350 and so are the radii in line 500.

     Replace "exp(z)" in line 320 by "sin(z)", rem out line 420, reactivate
line 440 by deleting the apostrophe.  Run the program.  Some of the points are
off-screen, so change the 3's in line 220 to 4's and run the program again.
There's a sine curve of another color!  Changing the 50 in line 350 to 100,
and the 200 in line 500 to 400, makes it look better, I think.



Features learnt in this lesson:
     use of nested loops
     dim for rectangular arrays
     some more about print
     passing rectangular arrays to and from subroutines
     syntax of subroutine output
     free use of complex numbers in UBASIC
     #i
     circle

                       THE END
Appendix IA:  UBASIC 8.84 Instructions, operators, etc.
--------------------------------------------------------
--------------------------------------------------------


System control                Run control
---------------               ------------
ubibm[32]                     run       beep
system                        stop      Pause      (The key, not the word)
doscmd                        cont      Ctrl--Break  (A 2-key combination)


Program control
----------------
for/to/step/next        if/then/else/endif      cancel
loop/endloop            elseif                  inkey
repeat/until            jump                    *
while/wend              goto
                        on error goto

Subprograms
------------
gosub  return  fn  local  *  def


Mathematical connectives, functions and  constants
---------------------------------------------------
+   -   *   /   \   ^   @   =   <>   <   >   <=    >=   and   or   not
#e   #eps   #euler   #i   #pi
sqrt     log  exp     sin  cos  tan  asin  acos  atan     sinh  cosh
besseli  besselj     int  ceil  floor  fix  round     abs  sgn  even  odd
rnd  randomize     max  min     num  den  cvr     im  re  arg  conj  absadd
absmax     combi  factorial  !  pi  sft     gcd  lcm  res  reduce  prm
prmdiv  nextprm  eul  kro  mob  moeb  modinv  modpow  modsqrt     irnd  isqrt


Graphics
---------
screen  view  window     pset  line  circle  paint  put  get
gcolor  color  dot     gsave  gload     glocate  gposx  gposy  gsize  gprint
mapx  mapy     roll


I/O
----
input  read  data  restore     print  using  tab  spc  alen  locate
input$  inp  out   + = {for redirection of output)


Hardcopy
---------
llist  lprint  lvlist  lxref  lvxref  ldir  llocate  copy


Editing
--------
save  asave  load  append  kill revive  new  rename
auto  renum     delete  edit     rem  '  stop  cont  skip     list     free
tron  troff  vlist  vchg  xref  vxref


String handling
----------------
"  +  left  mid  right  cutspc  cutlspc     lower  upper     eval  val
asc  chr  str  hex  len     decode  encode     instr  instr2  input$  strinput


File handling
--------------
open  close  as  input  output  append     set  file  input#  print#  eof
exist  rename  kill  restore  strinput  file1  file2  file3  load  save  asave
new  files


Utilities
----------
word  point (IMPORTANT)    pause  beep  end  nop     clr  dec  inc  neg  swap
cls   clr time   time  time1000  date     console  key     attrib  type
posx  posy     getenv  dir  doscmd     freeze  melt


UBASIC's polynomial construct
------------------------------
ccoeff  coeff  deg  diff  lcoeff  modulus  monic  poly  val  _x


Arrays
-------
dim   clr block   erase   find   neg block   swap block


Expanded-memory arrays          Packets           Machine-language programs
-----------------------         --------          --------------------------
ema                            left              bload
emaword                        mid               call
useema                         right
word                           pack
                               member


Bit operations
---------------
bit  bitand  bitcount  bitor  bitxor  bitset  bitreset  bitreverse
defseg  peek  peeks  peekw  poke  pokes  pokew  varptr

Appendix IB:  The manual for UBASIC 8.84
------------------------------------------

     The manual is in the file UBHELP.XXX.  It  consists of several parts, the
largest one being a reference that gives short descriptions of all of UB's
instructions.  The parts are: (the pagination is for the PCBOOK-printed
version)
           Pp.    1-19: A description of UBASIC 8.84.
                 19-62: An alphabetical list of all the UB instructions, with a
                             short description of each one.
                 62-68: A 13-lesson tutorial for UBASIC.
                 69-72: A description of some of the number-theoretical
                             programs that are distributed with UB.
                 72-74: Two appendicies: How numbers and arrays are
                             represented in memory, and how UB's mathematical
                             functions are calculated.
                 74-75: General information about UBASIC from Professor Yuji
                             Kida, its primary author; and thanks to others
                             who have contributed to it.

     The manual may be viewed during a UBASIC working session by using the on-
line help system, as described in Lesson 4 of this Introduction.  Furthermore,
UBHELP.XXX is an ASCII text file and so may be displayed on the screen, or
printed on paper, by using appropriate DOS instructions.  For example you may,
at the DOS prompt (not when working inside UBASIC), enter the instruction
                 type ubhelp.xxx
or
                 copy ubhelp.xxx con   .
The text may scroll by too quickly to be read.  The instruction
                 type ubhelp.xxx|more
will cause it to be displayed one screenful at a time.  An instruction such as
                 type ubhelp.xxx >prn
should get the whole manual printed on paper.

     Since the manual is 75 pages long, it may be more convenient to have it
printed in a compact form that uses only 19 sheets of paper.  This may be done,
with some printers, using PC Magazine's free utility program PCBOOK.  (It
works on Laserjet II printers and, I think, on some other laser or LED-type
page printers.  It does not work on my dot-matrix printer.)  PCBOOK prints the
text in "booklet format" - 4 pages of text will be printed on each sheet of
paper, 2 pages to a side; and the pages will be ordered so that the whole set
of sheets may be cut in two and then stapled together to form a booklet.  The
simplest way to do this is to have both the files UBHELP.XXX and PCBOOK.EXE
(which accompanies this Introduction) in your current directory.  Then enter -
at the DOS prompt - the instruction
                 pcbook ubhelp.xxx/p/w
and follow the instructions that will appear on your screen.  (The optional
"/p" gets the pages numbered, while "/w" causes long text lines to wrap
properly.)

