Before we dive into subscripts this chapter, we'll give you the answers to the problems at the end of chapter seven. Here is the program listing for the 1000 random integers from 0 to 9 (notice how we used blank lines to make it a little easier to read):
RANDOMIZE TIMER / 3 FOR N = 1 TO 1000 NUM = INT(10 * RND) IF NUM <> 0 THEN GOTO TRYONE LET ZERO = ZERO + 1 GOTO NEXTNUM TRYONE: IF NUM <> 1 THEN GOTO TRYTWO LET ONE = ONE + 1 GOTO NEXTNUM TRYTWO: IF NUM <> 2 THEN GOTO TRYTHREE LET TWO = TWO + 1 GOTO NEXTNUM TRYTHREE: IF NUM <> 3 THEN GOTO TRYFOUR LET THREE = THREE + 1 GOTO NEXTNUM TRYFOUR: IF NUM <> 4 THEN GOTO TRYFIVE LET FOUR = FOUR + 1 GOTO NEXTNUM TRYFIVE: IF NUM <> 5 THEN GOTO TRYSIX LET FIVE = FIVE + 1 GOTO NEXTNUM TRYSIX: IF NUM <> 6 THEN GOTO TRYSEVEN LET SIX = SIX + 1 GOTO NEXTNUM TRYSEVEN: IF NUM <> 7 THEN GOTO TRYEIGHT LET SEVEN = SEVEN + 1 GOTO NEXTNUM TRYEIGHT: IF NUM <> 8 THEN GOTO ISNINE LET EIGHT = EIGHT + 1 GOTO NEXTNUM ISNINE: LET NINE = NINE + 1 NEXTNUM: NEXT N PRINT ZERO; "Zeros", FOUR; "Fours" PRINT ONE; "Ones", FIVE; "Fives", EIGHT; "Eights" PRINT TWO; "Twos", SIX; "Sixes", NINE; "Nines" PRINT THREE; "Threes", SEVEN; "Sevens " END
Notice that we used a different variable to represent each digit that could be generated, and the somewhat long series of IF...THEN statements to assign the digit to the appropriate variable. We will show you this program again later in this chapter, but using subscripts. It will bring the program to less than half of its current size. Also notice the size of our FOR...NEXT loop. The computer really doesn't care how long it is, as long as it has a FOR and a NEXT. Our indentation help us make sure that there is one of each.
Let's get to the 100 coin tosses. Here is the version for the 0.5
"breakpoint" method. Notice again our use of tabs and blank lines to
enhance the readability:
RANDOMIZE TIMER / 3 FOR FLIP = 1 TO 100 COIN = RND IF COIN < .5 THEN GOTO ISHEADS LET TAILS = TAILS + 1 GOTO NEXTFLIP ISHEADS: LET HEADS = HEADS + 1 NEXTFLIP: NEXT FLIP PRINT HEADS; "Heads, and "; TAILS; "Tails." END
Notice that we don't do any calculations to the random number, just check its
value. Here is the other method of converting the random number to either a 1 or
RANDOMIZE TIMER / 3 FOR FLIP = 1 TO 100 COIN = RND COIN = INT(2 * COIN) + 1 IF COIN = 1 THEN GOTO ISHEADS LET TAILS = TAILS + 1 GOTO MOREFLIP ISHEADS: LET HEADS = HEADS + 1 MOREFLIP: NEXT FLIP PRINT HEADS; "Heads, and "; TAILS; "Tails." END
At the end of chapter seven, we developed a program to find the average of a list of numbers, and then determine the distance of each element from the average. As you recall, the program we developed wasn't too bad for ten elements, but then we wanted to find out for a list of 100 elements! This requires a program that is 104 lines long and contains 101 different variables. To handle something like this, QBASIC has implemented what are called subscripted variables. A subscripted variable in QBASIC looks like this: A(1) and is pronounced "A Sub One". The subscript is placed in parentheses after the variable being subscripted. That may not seem too impressive, but the subscript itself can be a variable, and can be as large as necessary! For our first averaging program, we would need 10 numbers ranging from A(1) to A(10). In the second example, we could store the 100 numbers as A(1) to A(100). In both cases, the values are all stored in the variable A, and the subscript could be generated with a FOR...NEXT loop.
A variable that has its data stored in subscript form is called an array. We have been talking about one-dimensional arrays so far, but QBASIC allows multi-dimensional arrays. For example, a two- dimensional array would look like A(1,2), and a three-dimensional array would look like A(4,3,6).
Let's can the chatter and get into some programming. Here is the first finger exercise for this chapter:
FOR I = 1 TO 10 READ A(I) NEXT I FOR I = 1 TO 10 LET X = X + A(I) NEXT I LET X = X / 10 FOR I = 1 TO 10 PRINT A(I), A(I) - X NEXT I DATA 51, 54, 56, 81, 79, 12, 60, 34, 67, 19 END
This program does the same thing as the one in chapter 7, but takes 8 fewer variables. Go ahead and run the program. Now we'll adjust the program to use 20 elements. The green lines are the changed or new ones:
FOR I = 1 TO 20 READ A(I) NEXT I FOR I = 1 TO 20 LET X = X + A(I) NEXT I LET X = X / 20 FOR I = 1 TO 20 PRINT A(I), A(I) - X NEXT I DATA 51, 54, 56, 81, 79, 12, 60, 34, 67, 19 DATA 16, 27, 80, 25, 13, 97, 52, 44, 5, 64 END
Now go ahead and run the program. Hey! What happened? Well, you get a "Subscript out of range" error! Why is that? It's because the computer needs to have a separate memory location for each element of the array, and large arrays can take up a lot of memory. The computer will automatically set aside ten "slots" for each subscripted variable, since ten does not take up too much memory. But what if we need, say, 100 slots? How do we tell the computer to set aside the necessary memory locations? We use the DIM command. DIM is short for Dimension. DIM tells the computer how much memory to reserve for an array. There is no harm in reserving more memory than is actually needed, provided you don't exceed the memory capacity of QBASIC. Here is what a DIM command looks like:
It looks just like a subscripted variable. The number inside the parentheses tells the computer the maximum number of subscripts you will use for that variable. If you try to use a larger one later on in the program, you will get that "Subscript out of range" error again. Let's fix up our little program to tell the computer to expect an array of 20 elements. Add this line at the very top of the program:
Now you may run the program. DIM commands are executed by QBASIC, so the DIM command must come before you try to put anything into the array. It is customary to put your DIM's at the beginning of the program.
Remember that we said we would rewrite our "1000 random digits" program using subscripted variables? Let's do it now. The first thing we need to do is clear out any program in memory. In our new program, we don't really need to tell the computer that we are using an array, since we are only going to use ten slots. However, it's a good idea to do it anyway so that you or anyone else who comes along later will know that arrays are being used. All we need to do is generate the digits and assign them to the array. Here is the first part of the program:
DIM A(10) FOR NUM=1 TO 1000 LET X = INT(10 * RND + 1) LET A(X) = A(X) + 1 NEXT NUM
Notice in line 3 how we generate the integers from 0 to 9 "on the fly"? Our random integer is assigned to the variable X. That X is then used as the subscript to the variable A. The A variable keeps a count of how many times each integer is generated. Just in those four lines, we have eliminated the long IF...THEN series that we had in the original program! Some of you may have noticed that zero can be used as a subscript, as it is here. All we have to do now is to print out the results. Here is the rest of the program:
FOR NUM=0 TO 9 PRINT NUM;"Appeared "; A(NUM); "Times." NEXT NUM END
Much simpler now, isn't it? Is the power of subscripted variables (also called arrays) becoming apparent? What took 46 lines to do without an array takes only 9 with it.
We will now introduce an algorithm that will probably be quite useful in many programs you write. Frequently, you will need to sort a set of numbers into either ascending or descending order. Usually, the sorting algorithm is part of a larger program. For example, one program that I have written in QUICKBASIC keeps track of all the employees in a medium-sized company. Each employee has his or her own employee number. As employees are added and removed, the list tends to get out of numerical order. To fix the situation, I added a menu option to re-sort the data either by employee number or by last name. The last-name sort is quite a bit more complex, but we will show you how it can be done when we discuss alphanumeric (or string) variables in future chapters. But for now, we have all of the necessary tools to generate and sort a list of numbers. We will show you how to sort a list of numbers in this chapter, and write the actual program in the next chapter.
Let's suppose we have a list of 7 numbers in an array:
We need to sort this list into decending order. You would probably scan the list from left to right to find the largest value, 19. You would then scan again for the next largest, 18. You would repeat this process until you had completely sorted the array.
Sounds simple, doesn't it? Well, there is only one teensy weensy problem. The computer can't "see" all of the values. It must follow a more detailed set of instructions, as it can only look at two numbers at a time. Here is how the instructions would go:
Compare the first number to the second. If the first is larger, leave the numbers where they are. If the first is smaller, exchange the two numbers. If they are equal, leave them alone. Now compare the first with the third. If the first is greater than or equal to the third. leave them alone. If the first is less than the third, swap them around. Now compare the first to the fourth in a similar manner. Continue until the first number has been compared to all of the following elements.
This compare and swap routine described is called one pass through the array. When this first pass is completed, the first element has the largest number in it. There may be other elements with the same value, but none are greater. After the first pass, our list would look like this:
You can see that the first number is the largest. Now we need to continue by comparing the second number to all remaining numbers, by doing the same thing. After our second pass, the array will look like this:
The computer continues the algorithm until we get to the end of the list, after which the array will look like:
Those of you familiar with sort algorithms will recognize this as the exchange sort.
Well, we've covered quite a bit in this chapter, so we'll break here and continue our discussion of sorting in chapter nine. In the meantime, here is a program for you to try:
Generate 100 random numbers ranging from 25 to 50, and calculate the standard deviation of the group. Standard deviation indicates how "spread out" or "scattered" the data is. To calculate standard deviation:
1.) Find the average of the list
2.) Subtract each item in the list from the average, and square the difference
3.) Add up all of the squared differences
4.) Divide the sum of the squared differences by the number of items in the list (100 for our program)
5.) Take the square root of the quotient.
HINTS: When the program is written correctly and you have a good random number generator, your answers should range between about 6.9 and 7.5 each time you run the program. Don't forget to use RANDOMIZE TIMER / 3 to seed the random number generator each time the program is run. To find the square of a number, use the following operator: (number)^2 or if necessary ((number)^2) and make sure you have the same number of closing parentheses as you do opening ones. To find the square root of a number, use SQR(number).
In our solution, we will show you a neat little trick with the DIM command and FOR...NEXT loops that allow you to change the number of items by either changing one line or using an INPUT statement.
If you want to try to write the sort program on your own, go ahead! Here is a hint or two: It uses only one array, and nested loops to cycle through the array. The initial value for the inner loop is the current value of the outer loop plus one.
See you next chapter!
Introduced in this chapter:
Concepts: Arrays and subscripted variables,
Dimensioning large arrays, multi-dimensional arrays.