Think of a function as a little trading booth: You give something to the merchant and you get something else in exchange.

Examples:

The square root function --You supply a number, say X, and you get back the square root of X. You give 4, you get back 2; you give 9, get back 3; give 2.25, get back 1.5; and so on.

The absolute value function -- You supply any number and get back the
same number with no sign (**unsigned**). You give any positive number
(or 0) and get the same number back. Supply a negative number, say -X and
get X. Give 1, get 1; give -10, get 10; give -1.5, get 1.5; etc.

These are examples of numerical functions -- put in a number and out comes a number. This is the only kind of function we will consider in this chapter. In Chapter 9 you will learn about string functions.

The value you feed into a function (its input value) is called the **argument;**
the **function value** (its output value) is referred to in this way:

<function name>(<argument>)

Examples:

--We give the name SQR to the square root function. If X is positive (or 0), SQR(X) is just the number which, multiplied by itself, equals X. That is:

SQR(X) · SQR(X) = X

Trying to call SQR(X) for some negative value of X gives you an FC error message (ILLEGAL FUNCTION CALL).

--We give the name ABS to the absolute value function. The value you get when you "plug in" (as mathematics teachers say) X is called ABS(X). ABS(1) is 1 ; ABS(2.3) is 2.3; ABS(-17) is 17.

If you specify an exact value for the argument, the function gives you a definite value. But you can also call a function with a variable or other numerical expression in the argument; then the function does not have a specific value until the variable or expression is evaluated.

Examples:

PRINT ABS(X*Y)

IF (SQR(A/B)>ABS(G)) THEN 40

LET HA+ABS(OS)

IF ABS(ATN(X)>SQR(COS(Z)+1) THEN SIN(X)+-SIN(X)

Other numerical functions and calculations of derived mathematical functions (secant, inverse hyperbolic cotangent, etc. are given in Appendix C.

Certain functions (called **intrinsic functions)** are built into
Standard BASIC. The Sorcerer recognizes their names where it sees them,
without having to be told how the functions work. These names are all **reserved
words.** (When the Sorcerer sees an intrinsic function it knows it is
not dealing with an array, despite the parentheses, since no array name
can contain a reserved word.)

You can also define your own functions with a special statement, the DEF statement. The DEF statement tells the Sorcerer that a certain name is the name of a function, rather than an array, and it also tells the Sorcerer how the function works.

The DEF statement has this format:

DEF <function name>(<variable>)=<expression>

The function name obeys these rules:

- The name must have at least three characters.
- The first two characters must be the letters FN.
- The third character must be a letter; others must be alphanumeric.
- The name cannot contain any reserved words.
- We strongly recommend using no more than two characters after FN.

The expression can be any numerical expression that contains the variable. The variable is called a "dummy variable"; it need not be the same when later used. As with all numeric variables, we limit the part after FN to two characters to avoid confusion and to facilitate conversion to other forms of BASIC.

You may wish to define your own square function to use in a program:

10 DEF FNSQ(M)=M*M

20 PRINT

30 FOR X=1 TO 10

40 PRINT FNSQ(X);

50 NEXT X RUN 1 4 9 16 25 36 49 64 81 100

Notice that while FNSQ was defined with the variable M, it was later called up with the variable X.

You may use the derived functions of Appendix D with DEF statements.

Examples:

Secant: DEF FNSC(M)=1/COS(M)

Inverse Hyperbolic Cotangent: DEF FNAR(X)=LOG((X+1)/(X-1))/2

While it might seem more convenient to call your function FNARCCOTH to distinguish it from other functions, as far as the Sorcerer is concerned, FNARCCOT and FNARCSEC are the same function. There are enough two-letter combinations that you won't run out of names for variables in one program.

The INT function turns any number into an integer (whole number). For an
integer, INT(X)= X. Otherwise, if X is positive you get INT(X) by throwing
away the fractional part of X (**truncating**), and if X is negative
you get INT(X) by adding -1 and **then** throwing away the fractional
part.

Examples:

INT(1.5)= 1

INT(-3.5) =-4

INT(-1)= -1

INT(.00001)= 0

INT(1)=1

INT(8.00001)=8

INT(-8.00001)=-9

INT(-.00001)=-1

INT(0)=0

INT(478.006)= 478

INT(-478.006)=-479

INT(.999999)=0

Notice that the INT function does not round numbers. Use the function to round numbers to the nearest integer by adding .5 to the expression, as in this program.

10 PRINT TAB(10);"NUMBER";TAB(20);"NUMBER ROUNDED"

20 PRINT

30 FOR X=1 TO 10

40 READ NR

50 PRINT TAB(10); NR;TAB(20); INT(NR+.5)

60 NEXT X

70 DATA 3.4,3.5,395.803,.49,.499999,.5,-1,-6.4,-6.6,-6.5

RUN

NUMBER NUMBER ROUNDED

3.4 3

3.5 4

395.803 396

.49 0

.499999 0

.5 1

-1 -1

-6.4 -6

-6.6 -7

-6.5 -6

Look at the last entry. As you can see, this method of rounding does not work end with a negative number that ends in exactly .5. You will see a way around the problem in a moment.

Use the INT function to round a positive number to any desired number of decimal places (or to any multiple of ten). Shift the decimal point to the end of the number (by multiplying or dividing by the correct power of ten), add .5, use the INT function to truncate the resultant number, and then shift the decimal point back to where it was (by now dividing, if you multiplied previously, and multiplying, if you divided, by the same power of ten).

10 PRINT

20 INPUT "ENTER A NUMBER";A

30 PRINT

40 PRINT "HERE IS THE NUMBER ROUNDED:"

50 PRINT "TO HUNDREDTHS" INT(A*100+.5)/100

60 PRINT "TO TENTHS" INT(A*10+.5)/10

70 PRINT "TO THE NEAREST WHOLE NUMBER" INT(A+.5)

80 PRINT "TO THE NEAREST TEN" INT(A/10+.5)*10

90 PRINT "TO THE NEAREST HUNDRED" INT(A/100+.5)*100

RUN

ENTER A NUMBER?348.778

HERE IS THE NUMBER ROUNDED:

TO HUNDREDTHS 348.78

TO TENTHS 348.8

TO THE NEAREST WHOLE NUMBER 349

TO THE NEAREST TEN 350

TO THE NEAREST HUNDRED 300

You may isolate individual digits of a number by using INT. You want to isolate the third digit of a seven-digit number, say 7654321. Truncate the number after the third digit:

INT (7654321/10000)= 765

Truncate the same number after the second digit and multiply that value by 10 to have numbers of the same length:

1l\lT(7654321/100000)·10=760

Subtract the second from the first, and the result is that third digit you were looking for:

765-760 = 5

10 REM A PROGRAM TO FIND THE NTH DIGIT OF A 7-DIGIT NUMBER.

20 PRINT

30 INPUT "GIVE ME A 7-DIGIT INTEGER";

40 INPUT "WHICH DIGIT SHALL I ISOLATE";N

50 PRINT

60 PRINT "DIGIT #"N"IS"INT(A/10^(7-N))-INT(A/10^(8-N))*10

RUN

GIVE ME A 7-DIGIT NUMBER?7654321

WHICH DIGIT SHALL I ISOLATE?3

DIGIT # 3 IS 5

In line 60 you could set off the two strings from the variable N with semicolons, this way:

60 PRINT "DIGIT #";N;"IS"INT(A/10^(7-N))-INT(A/10^(8-N))*10

We leave the semicolons off to show you that the absence of a delimiter between string and numeric variable produces the same result as if a semicolon were present. That is, the two versions of line 60 are equivalent.

The SGN function returns 1 for positive expressions, -1 for negative expressions and 0 for expressions with value 0.

Examples:

SGN(923·759)=1

SGN(-3·0007)=-1

SGN(0)=0

Now, here is the method, promised earlier, to round completely accurately any expression. Round the absolute value of the expression and multiply by the sign of the expression.

10 REM A PROGRAM TO ROUND ANY NUMBER

20 PRINT

30 INPUT "INPUT ANY NUMBER";A

40 PRINT "HOW DO YOU WISH IT ROUNDED (ENTER .01 FOR"

50 PRINT "HUNDREDTHS, .1 FOR TENTHS, 1 FOR ONES, 10 FOR"

60 PRINT "TENS, ETC.)";

70 INPUT N

80 PRINT "YOUR NUMBER ROUNDED TO THE NEAREST"N"IS ";

90 PRINT INT(ABS(A)/N+.5)*N*SGN(A)

RUN

INPUT ANY NUMBER? 123.456

HOW DO YOU WISH IT ROUNDED (ENTER .01 FOR

HUNDREDTHS, .1 FOR TENTHS, 1 FOR ONES, 10 FOR

TENS, ETC.)? .01

YOUR NUMBER ROUNDED TO THE NEAREST .01 IS 123.46

RUN

INPUT ANY NUMBER? -6.5

HOW DO YOU WISH IT ROUNDED (ENTER .01 FOR

HUNDREDTHS, .1 FOR TENTHS, 1 FOR ONES, 10 FOR

TENS, ETC.)? 1

YOUR NUMBER ROUNDED TO THE NEAREST 1 IS -7

RND produces random numbers. Give it a positive **argument **(the
number within the parentheses) and it generates a sequence of random
numbers, each one between 0 and 1. It doesn't matter what positive number
you use for the argument: each time you call the RND function, it produces
a different random number between 0 and 1.

Example:

10 INPUT X

20 PRINT "RANDOM NUMBER="RND(X)

30 GOTO 10

RUN

? 1

RANDOM NUMBER= .245121

? 4

RANDOM NUMBER= .305003

? 986

RANDOM NUMBER= .515163

? 1

RANDOM NUMBER= 1.7514E-03

? .0008

RANDOM NUMBER= .0583136

For each input you get a different random number, apparently not dependent on the seed. (The argument for RND is often called the seed). Try running this program to see a set of random numbers:

10 FOR X=l TO 50

20 PRINT RND(X);

30 NEXT

Run the program several times to verify that it produces a different set each time. Now change line 20 to read

20 PRINT RND(1);

and run that several times to verify that it does not matter what number
is used within the parentheses,** so long as it is positive.**

Each negative number, however, does a strange thing. Each produces one number between 0 and 1 which always comes out the same. RND(-50), for example, is always .308606, while RND(-3) is always .308605. Change line 20, above, to

20 PRINT RND(-X);

see the interesting results.

RND(0) always returns the most recent number called up by the RND function, the last time you used it, no matter when that was (so long as you didn't reset the Sorcerer or turn it off).

Now how do you use these? If you want to generate different random numbers in a program, use a positive seed, usually the same one each time (as in the SORCERER'S DICE program, below). If you want to generate a repeatable sequence (which you can use to test your program), first initialize the program by giving RND a negative seed. When the program appears to work, remove the statement that gives RND its negative seed.

That is, it is a deliberate part of Standard BASIC that each negative number used as seed produces the same series. For testing a program, you may wish to see the same sequences repeated until the bugs are out of the program. Then, later, to use the program for its designed purpose, you wish to produce truly random sequences, beyond the operator's control.

For example, this program gives a non-repeating set of random numbers. Each run of the program gives a new and different set.

10 FOR X=1 TO 50

20 PRINT RND(1);

30 NEXT X

Run the program several times to see that each set of random numbers is different. But add this line

5 Q=RND(-1)

and each time you run the program you get the same set of numbers.

You can use a combination of RND and INT to produce numbers in any range you wish.

Examples:

INT(RND(X)*10) generates a random whole number between 0 and 9.

INT(RND(X)*1010)/10+100 generates a random number, with one

decimal place, between 100.0 and 200.0

inclusive.

(In each case X is any positive number.)

You can use these functions for** games simulation.** To simulate a
number of dice throws, for instance, use this program:

10 REM SORCERER'S DICE

20 PRINT

30 INPUT "HOW MANY THROWS OF THE DICE";Y

40 PRINT

50 PRINT "THROW #";TAB(20);"THROW";TAB(40);"TOTAL"

60 PRINT

70 FOR X=1 TO Y

80 LET B=INT(6*RND(1)+1)

90 LET C=INT(6*RND(1)+1)

100 PRINT X;TAB(20);B;"+";C;TAB(40);B+C

110 NEXT X

By the way, RND does not produce **"real"** random
numbers: it produces something called** pseudo-random **numbers. These
numbers are random enough for most purposes, however. If you choose enough
random numbers between 0 and 1, they should theoretically tend to average
.5. Run this program to see how "good" the Sorcerer's random
number generator is. Let it go for a long time, say to 50,000, before
drawing any conclusions, and try the program several times.

10 NR=0:TL=0:REM INITIALIZE COUNTER AND ACCUMULATOR

20 PRINT"TRIAL","RANDOM NUMBER","AVERAGE"

30 PRINT

40 NR=NR+1

50 RN=RND(1)

60 TL=TL+RN

70 AV=TL/NR

80 PRINT NR,RN,AV

90 GOTO 40

Writing to the screen greatly slows down the CPU (the Sorcerer's Central Processing Unit, a Z80 microprocessor). You can speed up this program by just having the results printed when they yet close to .5 and seeing how many trials that takes. Add these statements:

75 X=INT(TL*10000)

80 IF X=5000 OR X=4999 THEN PRINT NR,RN,AV

When you run the program, you may get tired of staring for a long time
at a blank screen. Hit **CTRL C **, issue the** direct mode**
command

PRINT NR,RN,AV

to see where the program is, and then type CONT. You may look at the results each hundred trials by adding one more statement:

85 IF INT(NR/188)-NR/100=0 THEN PRINT NR,RN,AV