# CHAPTER 8

## NUMERICAL FUNCTIONS

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.

## FUNCTION NOTATION

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 40LET 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.

## THE DEF STATEMENT

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:

1. The name must have at least three characters.
2. The first two characters must be the letters FN.
3. The third character must be a letter; others must be alphanumeric.
4. The name cannot contain any reserved words.
5. 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*M20 PRINT30 FOR X=1 TO 1040 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

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)= 1INT(-3.5) =-4INT(-1)= -1INT(.00001)= 0INT(1)=1INT(8.00001)=8INT(-8.00001)=-9INT(-.00001)=-1INT(0)=0INT(478.006)= 478INT(-478.006)=-479INT(.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 PRINT30 FOR X=1 TO 1040 READ NR50 PRINT TAB(10); NR;TAB(20); INT(NR+.5)60 NEXT X70 DATA 3.4,3.5,395.803,.49,.499999,.5,-1,-6.4,-6.6,-6.5RUN  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 PRINT20 INPUT "ENTER A NUMBER";A30 PRINT40 PRINT "HERE IS THE NUMBER ROUNDED:"50 PRINT "TO HUNDREDTHS" INT(A*100+.5)/10060 PRINT "TO TENTHS" INT(A*10+.5)/1070 PRINT "TO THE NEAREST WHOLE NUMBER" INT(A+.5)80 PRINT "TO THE NEAREST TEN" INT(A/10+.5)*1090 PRINT "TO THE NEAREST HUNDRED" INT(A/100+.5)*100RUNENTER A NUMBER?348.778HERE IS THE NUMBER ROUNDED:TO HUNDREDTHS 348.78TO TENTHS 348.8TO THE NEAREST WHOLE NUMBER 349TO THE NEAREST TEN 350TO 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 PRINT30 INPUT "GIVE ME A 7-DIGIT INTEGER";40 INPUT "WHICH DIGIT SHALL I ISOLATE";N50 PRINT60 PRINT "DIGIT #"N"IS"INT(A/10^(7-N))-INT(A/10^(8-N))*10RUNGIVE ME A 7-DIGIT NUMBER?7654321WHICH DIGIT SHALL I ISOLATE?3DIGIT # 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

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

Examples:

`SGN(923·759)=1SGN(-3·0007)=-1SGN(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 NUMBER20 PRINT30 INPUT "INPUT ANY NUMBER";A40 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 N80 PRINT "YOUR NUMBER ROUNDED TO THE NEAREST"N"IS ";90 PRINT INT(ABS(A)/N+.5)*N*SGN(A)RUNINPUT ANY NUMBER? 123.456HOW DO YOU WISH IT ROUNDED (ENTER .01 FORHUNDREDTHS, .1 FOR TENTHS, 1 FOR ONES, 10 FORTENS, ETC.)? .01YOUR NUMBER ROUNDED TO THE NEAREST .01 IS  123.46RUNINPUT ANY NUMBER? -6.5HOW DO YOU WISH IT ROUNDED (ENTER .01 FORHUNDREDTHS, .1 FOR TENTHS, 1 FOR ONES, 10 FORTENS, ETC.)? 1YOUR NUMBER ROUNDED TO THE NEAREST 1 IS  -7`

## THE RND FUNCTION

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 X20 PRINT "RANDOM NUMBER="RND(X)30 GOTO 10RUN? 1RANDOM NUMBER= .245121? 4RANDOM NUMBER= .305003? 986RANDOM NUMBER= .515163? 1RANDOM NUMBER= 1.7514E-03? .0008RANDOM 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 5020 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 5020 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 DICE20 PRINT30 INPUT "HOW MANY THROWS OF THE DICE";Y40 PRINT50 PRINT "THROW #";TAB(20);"THROW";TAB(40);"TOTAL"60 PRINT70 FOR X=1 TO Y80 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+C110 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 ACCUMULATOR20 PRINT"TRIAL","RANDOM NUMBER","AVERAGE"30 PRINT40 NR=NR+150 RN=RND(1)60 TL=TL+RN70 AV=TL/NR80 PRINT NR,RN,AV90 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`

The Trailing Edge