ugBASIC User Manual

Maths

This section provides a full explanation of using standard mathematical and trigonometric functions, as well an insight into how ugBASIC exploits numbers.

Arithmetic Priority Fast Min Max Relative Random

Arithmetical calculations

Traditional mathematical operation is very easy on ugBASIC, since it gives to the programmer all basic arithmetical operations. For example, this instruction will print out a simple 4 as a result:

PRINT 2+2

The ugBASIC language recognize various mathematical symbols, as follows:

  • + : the plus sign that always signals addition;
  • - : the minus sign, used for subtraction;
  • * : the asterisk sign for multiplication;
  • ** : the double asterisk sign for multiplication with a number that is a power of 2 (very fast on CPU);
  • / : the forward-slash symbol for division;
  • \ : the backward-slash symbol for division with a number that is a power of 2 (very fast on CPU);
  • ^ : the circumflex character as exponential symbol (raise this number to a given power);
The following two lines are equal:

a = 3^5
b = 3*3*3*3*3

The following logical operations can also be used in calculations:

  • MOD : is the "modulo" operator;
  • NOT : is the bit a bit / logical not;
  • AND : is the bit a bit / logical and;
  • OR : is the bit a bit / logical or;
  • XOR : is the bit a bit / logical exclusive or;
Note that ugBASIC uses the convention, very common in BASICs of the 1970s and 1980s, of considering Boolean logic as implemented through the so-called "two's complement".

In other words, the value FALSE is associated with a number composed of all 0s, in terms of bits. The value TRUE is, instead, associated with a number composed of all 1s, again in terms of bits. According to the 2's complement representation, a number composed of all ones is always equivalent to the number -1, regardless of how many bits the number is composed of, while a number composed of all zeros is always equivalent to zero.

According to this convention, there is a coincidence between bitwise and logical operations: in fact, a bitwise AND, applied to all the bits of the number, will be equivalent to the logical operation "and". And so with the remaining bitwise (/logical) operations.

See the chapter Values ​​and signs for more information on the two's complement convention.

Calculation priorities

Since arithmetical instructions are taken literally, ugBASIC uses a set of built-in priorities. So the following lines give the results 6 and 8, respectively:

PRINT 2+2*2 : REM Print 6
PRINT (2+2)*2 : REM Print 8

The ugBASIC language handles a combination of calculations that make up an "expression" in the following strict order of priority:

  • exponential (^) are always calculated first;
  • multiplications (*) and divisions (/) are then calculated in order of appearance, from left to right;
  • the the modulo operations (MOD) is elaborated;
  • additions (+) and subtractions (-) are calculated last, again in order, from left to right;
Note that logical operations above (NOT, AND, OR, XOR) will not be taken into account until after all the above calculations have been completed. Obviously, any calculation placed inside a pair of round brackets is evaluated first, and treated as a single number.

So the next calculation gives a result of 43:

PRINT 10+2*5-8/4+5^2 : REM Print 43

This is the order followed:

5^2 = 25
2*5 = 10
8/4 = 2
10+10 = 20
20-2 = 18
18+25 = 43

By adding two strategic pairs of brackets to the same calculation, the logical interpretation is transformed, resulting in an answer of 768 (!), like this:

PRINT (10+2)*(5-8/4+5)^2 : REM Print 768

This is the different order followed:

10+2 = 12
5-8/4+5 = 5-2+5
5-2+5 = 8
8^2 = 64
12*64 = 768

Fast calculations

Mathematical calculations typically generate a series of intermediate values, and can therefore sometimes be a little slow. There are three instructions that can be used to increase the speed when it is present a simple calculation:

  • INC - to increment a variable by 1;
  • DEC - to decrement a variable by 1;
  • ADD - to add any number to a variable;
INC command adds 1 to an variable, using a single instruction to perform the expression variable=variable+1 very quickly.

For example:
v=41 : INC v : PRINT v

Similarly to INC, the DEC command performs a rapid subtraction of 1 from an integer variable.

v=43 : DEC v : PRINT v

Finally, the ADD command can be used to add the result of an expression to a whole number variable. It is the equivalent to make a variable=variable+expression but performs the addition is faster. There is a more complex version of ADD, which is ideal for handling certain limits much more quickly than the equivalent separate instructions. When those other parameters are included,

ADD v,a,b TO t

is the equivalent to the following lines:

v=v+a
IF v<b THEN v=t: ENDIF
IF v>b THEN v=b: ENDIF

Here is an example:

v=0
REPEAT
   ADD v,1,1 TO 42
   PRINT v
UNTIL v == 43 : REM This loop is infinite because v < 43

Relative values

It is obvious that every expression has a value, but expressions are not restricted to whole numbers (integers), or any sort of numbers. Expressions can be created from real numbers or strings of characters. If you need to compare two expressions, the following functions are provided to examine them and establish their relative values.

MAX compares two expressions and returns the largest. It can be used with any type of expressions, but they cannot be compared if they are mixed.

PRINT MAX(99,1) : REM Print a 99
PRINT MAX("ugBASIC","AAAA") : REM Print "ugBASIC"

On the very same way, MIN compares two expressions and returns the smaller value of two expressions.

DEBUG MIN(99,1) : REM Print a 1
DEBUG MIN("ugBASIC","AAAA") : REM Print "AAAA"

Values and signs

To explain how ugBASIC treats signed numbers, it is necessary to make a brief excursus on the concept of “two's complement”. There are 256 possible values in a byte: 00 to FF (in hexadecimal). The range of an 8-bit unsigned number is 0 (00) to 255 (FF). The range of a 16-bit unsigned number is 0 (0000) to 65535 (FFFF), and so on. They are called unsigned numbers because they are zero or greater, i.e. there is no (minus) sign.

A signed number, on the other hand, can be negative or positive (or zero). The term "signed number" is used below to mean a two's complement number, so the range of an 8-bit signed number is -128 to 127. The values -128 through -1 are, in hex, 80 through FF, respectively. The values 0 through 127 are, in hex, 00 through 7F, respectively. So the minimum value of a signed number is 80 and the maximum value of a signed number is 7F. The range of a 16-bit signed number is -32768 (8000) to 32767 (7FFF) (8000 through FFFF are the negative numbers), and so on.

This may seem like a strange way of handling negative numbers, but this method has several useful properties:

  • same representation for positive numbers: the "overlap" of the ranges of 8-bit signed and unsigned numbers is, in hex, 00 to 7F, regardless of whether the number is signed or unsigned;
  • a bit for the sign: the most significant bit (bit 7 for an 8-bit number) is zero when the number is non-negative (0 to 127), and one when the number is negative;
  • zero is positive: in mathematics, zero is not a postive or a negative number, but in the computer world, things are less formal; so the term "positive number" typically includes zero because (a) all of the other possible values of a signed number whose most significant bit is zero are positive numbers, and (b) all of the other possible values for an unsigned number are positive numbers;
  • adding and subtracting is the same.
Any number can have one of three values: negative, positive or zero, and these are represented by the "sign" of a number. So the SGN function returns a value representing the sign of a number. The three possible results are these:
  • -1 if the value is negative;
  • 1 if the value is positive;
  • 0 if the value is zero.
So:

PRINT SGN(-42): REM Print -1

On the other side, ABS can be used to convert arguments into a positive number. ABS returns an absolute value of an integer or fractional number, paying no attention to whether that number is positive or negative, in other words, ignoring its sign.

PRINT ABS(-1): REM Print 1
PRINT ABS(1): REM Print 1

Random numbers

The easiest way to introduce an element of chance or surprise into a program is to throw some numbered options into an electronic "pot" and to allow ugBASIC to pull one out at random. After a number has been selected and used, it is thrown back into the pot once again. It then has the same chance as any other number offered for selection, when the next random choice is made.

The RND function generates integers at random, between zero and any number specified in brackets. If your specified number is greater than zero, random numbers will be generated up to that maximum number.

DO
   x = RND(WIDTH-1): REM you can use "RANDOM WIDTH" as an alternative
   y = RND(HEIGHT-1): REM you can use "RANDOM HEIGHT" as an alternative
   TEXT x, y, "UGBASIC AT RANDOM"
LOOP

In practice, the numbers produced by the RND function are not genuinely random at all. They are computed by an internal mathematical formula, whose starting point is taken from a number known as a "seed". This seed is set to a standard value whenever ugBASIC is loaded into your computer, and that means that the sequence of numbers generated by the RND function will be exactly the same each time your program is run.

This may well be acceptable for arcade games, where pre-set random patterns generated by RND can be used to advantage, but it is a useless system for more serious applications. The RANDOMIZE command solves this problem by setting the value of the seed directly. This seed can be any value you choose, and each seed will generate an individual sequence of numbers. RANDOMIZE can also be used in conjunction with the TIMER variable, to generate genuine random numbers.

The TIMER reserved variable is incremented by 1 unit every 50th of a second (on PAL systems) or by 1 unit every 60th of second (on NTSC systems), in other words, it returns the amount of time that has elapsed since your computer was last switched on. As explained above, this makes it a perfect "seed" to be used with the RANDOMIZE function, as follows:

RANDOMIZE TIMER

The best place to use this technique is immediately after the user has entered some data into the computer. Even a simple key-press to start a game will work perfectly, and generate truly random numbers.

Any problem?

If you have found a problem, if you think there is a bug or, more simply, you would like something to be improved, write a topic on the official forum, or open an issue on GitHub.

Thank you!