Chapter Six
Input Range Testing, Tolerances
KeyWord: BEEP



This chapter will start us off by learning how to check data that was input by an operator using an INPUT statement. Let's assume that you have a program that requires the user to input a positive number, and that zero can be allowed. What happens if the user enters in a negative number? How do you check it, and how can you correct it? Let's find out! Here is a section of program code that has our input checking property:

 


...

GETNUM:

PRINT "Enter a positive number";

INPUT A

IF A >= 0 THEN GOTO NUMOK

PRINT "You have entered a negative number! Try again"

GOTO GETNUM

NUMOK:

LET X=2*(A/D)

...

Let's trace through this program section to see what it does. When the program gets to the second line, it prints out the message indicating what the user needs to do. Line 3 then prints a question mark on the screen and waits for the user to type in a number. When the user enters the number, it gets assigned to the variable A, and the program continues to line 4. Here we have one of those wonderful IF...THEN commands. What it does is check the value of A to see if it is greater than or equal to (remember those from chapter 2?) zero. If it is, we have a valid response and the program jumps to line 7. If not, the program drops down to line 5 and prints out the "now look what you did" message. Then line 6 tells us to go to line 1, where the user is again asked to enter the positive number, and we do it all over again.

Now we get to write a "really neat" program. It actually calculates square roots. The method that is used is called "divide and average", and it works like this. Take the number you want to find the square root, and divide it by some arbitrary number. In our case, we'll divide it by 2. Now we take that answer, and divide the original number by it. Now we average the first answer with the new answer, and divide the original number by that result. We now take what we get and average it with the answer we got before. We continue this crazy cycle until the two answers are identical, in which case we will have the square root. Let's run through it using a real number so that you can understand what on earth is going on around here. We'll use 16 since it's a perfect square.

Take the 16 and divide it by 2. You get 8. Now take the 16 and divide it by the 8, and you get 2. Now average the 2 and the 8 to get 5. Now we divide the 16 by 5 and get 3.2. We average our new answer of 3.2 with our old answer of 5 to get 4.1. Now we divide 16 by 4.1 to get (approximately) 3.9. Now we average the 3.9 and the 4.1 to get 4. Now divide 16 by 4 to get 4. Since the new answer and the previous average are the same, we have arrived at the square root. Let's put that into QBASIC. We will start out by asking for a number, so our first lines will be PRINT and INPUT commands to get a number. Be sure to clear out any program that is in memory:

 



PRINT "Enter Number to Find Square Root";

INPUT NUM

You will notice that we have to keep track of two answers. We will refer to them as new answer and old answer. We'll use the somewhat descriptive variable names NEWANS and OLDANS to keep track of them:

 



LET OLDANS = NUM / 2

Next, we divided the original number by the old answer to get a new answer. We will also need a label here for our loop. We'll use an abbreviation of "Calculate Answer" without spaces (you can't have spaces in label names).


CALCANS:

LET NEWANS = NUM / OLDANS

Next, we average the two answers together.

 



LET OLDANS = (NEWANS + OLDANS) / 2

After that, we go back and do it again.

 



GOTO CALCANS

Now, we need to check when the answers are the same. We'll do that right after we do the division, so insert this line right after the LET OLDANS= line:

 



IF NEWANS = OLDANS THEN GOTO FINISHED

When we finally get the answer, all we have to do is print it out and end the program. Add this to the bottom of the program:

 



FINISHED:

PRINT "Square Root Of "; NUM; " Is"; NEWANS

END

Just to make sure you have it in right, here's what we have so far:

 


PRINT "Enter Number to Find Square Root";

INPUT NUM

LET OLDANS = NUM / 2

CALCANS:

LET NEWANS = NUM / OLDANS

LET OLDANS = (NEWANS + OLDANS) / 2

IF NEWANS = OLDANS THEN GOTO FINISHED

GOTO CALCANS

FINISHED:

PRINT "Square Root Of "; NUM; " Is"; NEWANS

END

Now go ahead and run the program, using the value of 16. Notice that almost immediately it calculates the square root? Let's do it again! Run the program and type in 1234321 when it asks. Right away, you get back the correct answer of 1111. For those of you who have the slower PC's and XT's, you may detect about a tenth of a second delay between pressing the Enter key and the computer coming back with the answer. That is because the computer is going through that loop 13 times, doing all those calculations. If you have a 200 Mhz Pentium system, you almost get the answer before you ask the question because it's so fast! Anyway, let's try another number! Run the program again, and type in 24. Hey! Who told the computer to take a coffee break? When do I get my answer? Well, you will never get your answer! To stop the computer, hold down the Ctrl key while you press the Break key. This is called the "Control-Break" sequence. You probably never would have guessed that in a kazillion years. Here is where we need to talk just a little bit about how a computer sees numbers (and letters, for that matter). In our numbering system, we have ten digits, zero through nine. Well, a computer runs on electricity, and the electricity can only be on or off. Therefore, a computer can only use two digits, zero and one. For the most part, the conversion between these two numbering systems is pretty much accurate and hassle free. For example, what we see as 47, the computer sees as 00101111. When you tell the computer 113, it is really thinking 01110001. However, when you tell the computer 0.3, it has to think 0.0100110011001100110011001100110011001100110011001100110011001... and has a headache, because that is a never-ending sequence. So, the computer has to chop it off at about 38 digits to keep from using too much memory, and yet still contain some accuracy. When it goes back and forth between the two numbering systems, it will sometimes generate this "rounding-off error", causing two things that are supposed to be exactly equal look like they aren't. This is the problem that our little program is having with the number 24. Well then, how do we fix that? Instead of checking if the two answers are equal, we will check to see if they are very, very, very close. How do we do that? Well, if two numbers are very close, when you subtract one from the other, you will get an answer that is very near zero. Let's fix up our program to take this "tolerance" into account. Replace the line that says

 

IF NEWANS = OLDANS THEN GOTO FINISHED

with:



IF ABS(NEWANS - OLDANS) < .00001 THEN GOTO FINISHED

Now if you run the program, it will work fine. Notice that we took the absolute value of the difference? That way, we would get a positive result no matter which way the numbers are. If the difference of these two numbers is less than 0.00001, a really really really small number, then we will assume that they are the same. However, there is a minor flaw with this method. As we find the square roots of larger numbers, the tolerance become apparently much smaller, because the answers are bigger. For huge numbers, say 30 digit numbers, we may still get the computer to lock up. We could use a slightly bigger number on the right side of the less-than sign, but that would reduce the accuracy of the result for the smaller answers. So how do we fix that? We can make the tolerance change by not using an actual number, but instead by using a percentage of the original number. This will make the tolerance very tight for small numbers, and loosen it for huge numbers. To do that, we simply multiply our original number by a small constant. The corrected line will look like this:



IF ABS(NEWANS - OLDANS) < .00001 * NEWANS THEN GOTO FINISHED

Now the answer will be within .001% of the original number. That's pretty accurate, isn't it? There is still a major problem with the program. Run it again, and try to find the square root of -16. Oh, look! Another coffee break! Why? Each time it finds a new answer, the sign changes! First positive, then negative, then positive again, and so on. It will never zero in on a number but jump around wildly as it tries to average a positive and negative number. If the two numbers are close, but one is positive and the other negative, it will average out to be close to zero. When you divide a number by another very small number, you get a very large answer, and then it will average the new large answer with the old small number. How do we stop this? We don't let the user enter a negative number. How? We showed you at the beginning of the chapter. See if you can figure it out first, but first notice that entering a zero will also give you a "Division by zero" error - we don't want that, either.

Here is the program segment you need to enter to do the job. Between the lines
INPUT NUM
LET OLDANS = NUM / 2

enter:

 



IF NUM > 0 THEN GOTO ENTEREDOK

BEEP

PRINT"Number must be greater that zero - Try again"

GOTO TOP

ENTEREDOK:

and at the top, add:

 



TOP:

Whoa! Look at the line that says "BEEP"! what does that do? What do you think it might do? Would you like to find out? Then type in BEEP in the immediate window and listen closely! To be completely technical, it produces an 800 Hz tone for 0.27 seconds. In real English, it makes the computer beep. I guess in this case you could call it an error alarm! It alerts the user that he has made an input error, and is accompanied by the "nice going, stoopid!" message. The user is then allowed to try again.

Just to make sure you have everything typed in correctly, here is the program in it's entirety:

 



TOP:

PRINT "Enter Number to Find Square Root";

INPUT NUM

IF NUM > 0 THEN GOTO ENTEREDOK

BEEP

PRINT "Number must be greater that zero - Try again"

GOTO TOP

ENTEREDOK:

LET OLDANS = NUM / 2

CALCANS:

LET NEWANS = NUM / OLDANS

LET OLDANS = (NEWANS + OLDANS) / 2

IF ABS(NEWANS - OLDANS) < .00001 THEN GOTO FINISHED

GOTO CALCANS

FINISHED:

PRINT "Square Root Of "; NUM; " Is"; NEWANS

END

If you want to see the intermediate answers, add the program line that's in color:
Download The Square Root Program Now!


TOP:

PRINT "Enter Number to Find Square Root";

INPUT NUM

IF NUM > 0 THEN GOTO ENTEREDOK

BEEP

PRINT "Number must be greater that zero - Try again"

GOTO TOP

ENTEREDOK:

LET OLDANS = NUM / 2

CALCANS:

LET NEWANS = NUM / OLDANS

PRINT "Intermediate Answer is"; NEWANS

LET OLDANS = (NEWANS + OLDANS) / 2

IF ABS(NEWANS - OLDANS) < .00001 THEN GOTO FINISHED

GOTO CALCANS

FINISHED:

PRINT "Square Root Of "; NUM; " Is"; NEWANS

END

That's all for this time, but here are some programs for you to try your hand at:

INPUT a three digit number, and print it's reversal. In other words, given 275, print 572. You will need input range checking for this program to work. An original number ending with zero (420) can be printed out without leading zeros (24 is okay, since the computer won't print 024). If you would prefer, you may print it out as a three-digit number (024), but the PRINT command will automatically put spaces between each number (that's okay). HINT: Use division and either the INT(x) or FIX(x) functions.

INPUT a four digit number and print its reversal. In other words, given 9371, print 1739. Use the same hint as above.

Given a positive number less that 20,000, (Use INPUT and error checking) determine if it is a prime number. A prime number can be divided evenly only by 1 and itself. A word of caution here. On the lower speed computer, the larger numbers (over 10,000) can take over a minute to calculate.



Next chapter, we will learn about random number generation, and talk about a major problem: storing large amounts of data in variables. See you next time!!

Introduced In This Chapter:
Keyword: BEEP

Concepts: Input range checking, tolerance, audible signaling.





Previous Chapter Next Chapter