LEARN TO PROGRAM WITH SMALL BASIC: An Introduction to Programming with Games, Art, Science, and Math (2016)
7. EMPOWERING PROGRAMS WITH MATH
If mathematics bores or scares you, that’s okay. You’ll soon realize how easy Small Basic makes it for you to write programs that do math for you. Many programs use only simple operations like addition, subtraction, multiplication, and division. For these types of problems, you need just the four basic math operators (+, –, *, and /). The asterisk (*) represents multiplication, and the slash (/) represents division.
Other programs need to use some of the math functions that you might have learned in algebra (like square root, absolute value, and trigonometric functions). Small Basic’s Math object provides these functions and many others.
If you don’t know what a square root or a trigonometric function is, don’t panic; you still can write programs using these functions. And it’s okay to skip some of the examples in this chapter, too.
To use any of the Math object methods, you’ll write a statement like this:
ans = Math.SquareRoot(16)
In this example, you call the SquareRoot() method and pass 16 to it (to find the square root of 16). The output, or result of a method, is called the return value. In this statement, the method’s return value is assigned to the ans variable (short for answer). In this chapter, you’ll learn about the Math object’s methods and how to put them to work.
The Math object has four methods related to exponents, but we’ll cover just SquareRoot() and Power() in this book.
SquareRoot() and Good Old Pythagoras
In this first example, we’ll find the length of the longest side, or hypotenuse, of a right triangle. If you call the lengths of the other two sides s1 and s2, the Pythagorean Theorem tells you that the length of the hypotenuse is the square root of the sum of each side squared. Here’s the equation:
We put this formula in the program in Listing 7-1 so you don’t have to think about it too much. Given the two side lengths of a right triangle, the following program uses the Pythagorean Theorem to calculate the length of the hypotenuse.
1 ' SquareRootDemo.sb
2 TextWindow.Write("Enter the length of side 1: ")
3 s1 = TextWindow.ReadNumber()
5 TextWindow.Write("Enter the length of side 2: ")
6 s2 = TextWindow.ReadNumber()
8 hypot = Math.SquareRoot(s1 * s1 + s2 * s2)
9 TextWindow.WriteLine("Hypotenuse = " + hypot)
Listing 7-1: Finding the length of a hypotenuse
This program prompts the user to enter the length of the first side (line 2) and then saves the input in s1 (line 3). It then asks for the second input and saves it in s2 (line 6). Then it computes the length of the hypotenuse (line 8) and displays the result (line 9). On line 8, notice how the square of s1 (and s2) was computed by multiplying s1 (and s2) by itself.
Here’s a sample run of our program. Remember that this program works only with right triangles:
Enter the length of side 1: 3
Enter the length of side 2: 4
Hypotenuse = 5
You can use Power() for all sorts of calculations that involve exponents, like taking 3 to the 5th power. You might see this written in math class as 35, which is the same as 3 × 3 × 3 × 3 × 3. The 3 is called the base, and the 5 is the exponent. Here’s how you could perform this calculation in Small Basic:
answer = Math.Power(3, 5)
Notice that Power() takes two arguments: the first is the base, and the second is the exponent. The result is saved in the answer variable. The second statement displays the output so you can check the answer.
Now let’s look at a program that’s a little more complicated. We’ll use the Power() method to show you how money grows. If you deposit P dollars at a bank that gives an interest rate of r percent, then at the end of n years you’ll have A dollars:
A = P × (1 + r)n
Without worrying about where this formula came from, let’s write a program that computes the value of A for given values of P, r, and n (entered by the user). Enter the program in Listing 7-2.
1 ' PowerDemo.sb
2 TextWindow.Write("Principal (in dollars)........: ")
3 P = TextWindow.ReadNumber()
5 TextWindow.Write("Interest rate (decimal form)..: ")
6 r = TextWindow.ReadNumber()
8 TextWindow.Write("Number of years...............: ")
9 n = TextWindow.ReadNumber()
11 A = P * Math.Power(1 + r, n)
14 TextWindow.Write("After " + n + " years, ")
15 TextWindow.WriteLine("you will have $" + A)
16 TextWindow.WriteLine("That fortune is almost as big as Batman's!")
Listing 7-2: Calculating how your money grows
Run the program to see how much money you’ll have in 20 years if you deposit $1,000 with an interest rate of 6%:
Principal (in dollars)........: 1000
Interest rate (decimal form)..: 0.06
Number of years...............: 20
After 20 years, you will have $3207.1354722128500
That fortune is almost as big as Batman's!
We admit it’s rather strange to see dollars and cents written with so many decimal places. In this case, you don’t need all those digits to the right of the decimal point. Next, you’ll learn how to round this long answer to the nearest dollars and cents.
TRY IT OUT 7-1
The circus is looking for talent, and they think you’re the one! They want to pay you $1 for balancing one cat on your head, $2 for balancing two cats on your head, $4 for balancing a third cat, and so on, doubling the money with each cat you add to the stack! Write a program to find out how much money you get when you have n number of cats balanced on your head, where n is entered by the user. Is it enough to retire and buy a cat mansion?
Sometimes you’ll need to round numbers in your programs. For example, if your program finds the average number of children per household in your neighborhood, you don’t want your program to display 2.25 (two and a quarter children per house). That wouldn’t make any sense!
The Math object gives you three methods that round or chop numbers: Round(), Floor(), and Ceiling(). See Figure 7-1 for a quick overview of what each method does to a number.
Round(x) returns the whole number (or integer) nearest to x. Floor(x) returns the integer that’s less than or equal to x, and Ceiling(x) returns the integer that’s greater than or equal to x. Experiment with each of these different methods to see what results you get.
Let’s use this rounding knowledge to fix the output of our interest calculator. Add the following statement after line 11 in Listing 7-2:
A = Math.Round(A)
After computing A, you round it and assign the rounded result back to A. When you run the program now with the same inputs, it will display $3207. Much better!
Figure 7-1: The rounding methods with example arguments and return values
Be careful when you use the Round() method if the fraction part of the number is exactly 0.5. In this case, the Round() method rounds to the nearest even integer (this is called banker’s rounding). For example, 0.5 and –0.5 are rounded to 0, 1.5 and 2.5 are rounded to 2.0, and –1.5 and –2.5 are rounded to –2. This is different from what you learned in algebra, where the 0.5 fractions always round up to 1! Even though it’s not what you’re used to, banker’s rounding is very common and is regularly used by bankers, which gives it its name.
But how can we make Small Basic round numbers the way you learned in school (where the 0.5 fraction is always rounded up)? We’ll do some fancy footwork using the Floor() method instead of the Round() method, like this:
Math.Floor(x + 0.5)
Using this trick, x represents whatever value you want to round. So if x is 0.6, then x + 0.5 = 1.1, and Floor(1.1) = 1. Cool! That’s exactly how we’d expect it to work.
But let’s say x is 2.5. If we just used Math.Round(2.5), we would get 2, which isn’t the result you would want if you wanted to use traditional rounding. We want to round up and get 3. Using our fancy trick, you’d get x + 0.5 = 3.0, and Floor(3.0) = 3. Now that’s more like it! This gets the values you’d expect if you wanted to round a number with a .5 fraction.
Rounding to the Nearest Hundredth
Let’s explore Listing 7-2 a bit more. Using Round() or Floor() on the answer gives you a whole number (dollars only). But what if you want to show the amount of money to the nearest penny? How can you make Small Basic round the answer to the nearest hundredth? Consider this statement:
Math.Floor(100 * x + 0.5) / 100
For example, if x = 2.8735, then 100 * x + 0.5 = 287.85, and the Floor() method returns 287. Dividing 287 by 100 is 2.87, which is the result we want.
You can also round to the nearest hundredth using this statement:
Math.Round(x * 100) / 100
Let’s use this second technique to round the answer from Listing 7-2 to the nearest penny. Add the following statement after line 11 in Listing 7-2:
A = Math.Round(A * 100) / 100
After computing A in line 11, the program rounds it to the nearest hundredth (nearest penny) and saves the rounded answer back in A. If you run the program now using the original inputs, the output will be $3207.14. Perfect! Now we’re talking money!
TRY IT OUT 7-2
Helen is having a tough time at her store. She uses a calculator to add the 6% sales tax to the purchase price. For example, if a customer’s total comes to $27.46, she multiplies 27.46 by 1.06 to get 29.1076. But should she charge the customer $29.10 or $29.11? She doesn’t have time to do these calculations herself! Her store keeps her much too busy!
Helen heard about your programming skills, so she’s coming to you for help. She needs a program that lets her enter the total purchase amount. Then she wants the program to add the sales tax, round the result to the nearest penny, and display the answer. Create this program for Helen.
Abs(), Min(), and Max() Methods
The Math object provides methods for you to find the absolute value of a number. When you calculate the absolute value of a number, you’re finding its distance from zero, which will always be a positive number. For example, the absolute value of both –1 and 1 is 1.
This code snippet shows you some examples:
Math.Abs(-2) ' = 2
Math.Abs(-3.5) ' = 3.5
Math.Abs(4) ' = 4
The Abs() method takes in a number (positive or negative) and returns that number’s distance from 0, or its absolute value. This return value is always a positive number. (In other words, Abs() removes the minus sign.)
For example, let’s say the user of your game needs to guess a secret number (10), but the guess doesn’t have to be exact. Instead, your game accepts any guess between 8 and 12. To check if the user’s guess is okay, you can test the absolute difference between the user’s guess (saved in theguess variable) and 10; that is Abs(guess - 10). If the result is less than or equal to 2, then your player’s guess is good. You’ll learn how to perform checks like this one using If statements in the next chapter.
Now let’s find the minimum or maximum of two numbers. The Min() method returns the lower of two numbers, and the Max() method returns the higher number:
Math.Min(5, 10) ' = 5
Math.Min(-3.5, -5.5) ' = -5.5
Math.Max(3, 8) ' = 8
Math.Max(-2.5, -4.7) ' = -2.5
You can use these methods to limit the numbers your user can input to your program. For example, if your program expects a number that’s less than 100, you can write this:
ans = TextWindow.ReadNumber()
ans = Math.Min(ans, 100)
Try it out! Run this code two times. The first time, enter a number less than 100, and the second time, enter a number greater than 100. What happens? Can you modify the code so the entered number can’t go below 0?
What if you want to find the minimum of three numbers? For example, let’s say you want to find the lowest score out of the three math quizzes you took last week. One way is to write this:
minScore = Math.Min(Math.Min(score1, score2), score3)
The inner Min() method finds the minimum of the score1 and score2 variables. That result and score3 are passed to the outer Min() method to determine which is lower: the first minimum (of score1 and score2) or score3. The final result is saved in the minScore variable.
TRY IT OUT 7-3
Your favorite potato chips are sold at three local stores; each bag is a different price. Write a program that prompts you to enter the price at each store and then displays the lowest price. Saving money means more potato chips for you!
The Remainder() Method
You can get the remainder from any division operation by using the Remainder() method. For example, Math.Remainder(10, 3) returns 1 because 10 ÷ 3 = 3 with a remainder of 1.
You can use the Remainder() method to test whether one integer (whole number) can be divided evenly by another, smaller integer. A remainder of 0 means that the larger number’s divisible by the smaller number (such as how 9 is divisible by 3). Knowing if there’s a remainder has all sorts of interesting uses. For example, if you want to check whether a number is even or odd, you can examine the remainder of that number divided by 2: if the remainder is 0, the number is even; otherwise, it’s odd.
To see the Remainder() method in action, let’s write a program that finds the number of dollars, quarters, dimes, nickels, and pennies in a given amount of money. To find the most efficient quantity of dollars and coins, you’ll need to start with the largest denomination (dollars) and work your way down the the smallest one (pennies). Listing 7-3 shows the complete program and includes example output in the comments. Read through the program, and see if you can figure out what happens when the input is 25.36.
1 ' Money.sb
2 TextWindow.Write("Enter an amount of money (such as 25.36): ")
3 total = TextWindow.ReadNumber() ' In dollars and cents = 25.36
4 cents = Math.Floor(total * 100) ' Total cents = 2536
5 dollars = Math.Floor(cents / 100) ' Number of dollars = 25
6 cents = Math.Remainder(cents, 100) ' Remaining cents = 36
7 quarters = Math.Floor(cents / 25) ' Number of quarters = 1
8 cents = Math.Remainder(cents, 25) ' Remaining cents = 11
9 dimes = Math.Floor(cents / 10) ' Number of dimes = 1
10 cents = Math.Remainder(cents, 10) ' Remaining cents = 1
11 nickels = Math.Floor(cents / 5) ' Number of nickels = 0
12 pennies = Math.Remainder(cents, 5) ' Number of pennies = 1
13 TextWindow.Write("$" + total + " = ")
14 TextWindow.Write("$" + dollars + ", ")
15 TextWindow.Write(quarters + "Q, ")
16 TextWindow.Write(dimes + "D, ")
17 TextWindow.Write(nickels + "N, ")
18 TextWindow.Write(pennies + "P.")
Listing 7-3: Finding dollar and coin denominations
Let’s walk through this program line by line to understand how it works. The user enters 25.36 (that is, 25 dollars and 36 cents) in response to line 2, so the total = 25.36. Line 4 computes the total cents as Floor(25.36 * 100) = 2536. This number is then divided by 100 to get 25 and saved in dollars (line 5), with a remainder of 36, which is saved in cents (line 6). Next, 36 cents is divided by 25 to get 1 quarter (line 7) and a remainder of 11 cents (line 8). The remainder of 11 cents is then divided by 10 to get 1 dime (line 9) with a remainder of 1 cent (line 10). Lines 11 and 12 compute the available nickels and the remaining pennies in the same way. The rest of the program (lines 13–19) displays the results. Figure 7-2 illustrates this program.
Figure 7-2: Illustrating the output of Money.sb
Let’s try a different amount and look at the output:
Enter an amount of money (such as 25.36): 23.78
$23.78 = $23, 3Q, 0D, 0N, 3P.
That’s pretty handy if you’re making change!
TRY IT OUT 7-4
Write a program that reads a three digit number and outputs each digit followed by its place value. For example, if the input is 368, the program should display this:
(Hint: if you divide 368 by 100, you get 3 with a remainder of 68. If you divide 68 by 10, you get 6 and a remainder of 8.)
Random numbers are used in many applications, like simulations and games. They’re also used for software testing (to see how a program responds to different input values) or to simulate random events (like the lottery).
The GetRandomNumber() method returns a random integer between one and the upper limit you pass to the method. Using this method, your program can generate random numbers that you can use in all sorts of exciting applications, for instance, to see whether a troll bops your hero on the head. Let’s look at some examples.
To simulate a roll of a die, write this:
dice = Math.GetRandomNumber(6)
TextWindow.WriteLine("You rolled: " + dice)
The variable, dice, contains a number between 1 and 6 that’s selected at random, similar to picking it out of a hat (but not the Hogwart’s Sorting Hat). Run the program several times to see for yourself.
To simulate the flip of a coin, you can write this:
coinFlip = Math.GetRandomNumber(2)
TextWindow.WriteLine("Outcome: " + coinFlip)
The variable coinFlip is either 1 or 2. The value 1 represents heads, and the value 2 represents tails (or the other way around; it’s up to you!).
To simulate rolling a pair of dice and finding their sum, you can write this code:
num1 = Math.GetRandomNumber(6)
num2 = Math.GetRandomNumber(6)
outcome = num1 + num2
TextWindow.Write("You got (" + num1 + "," + num2 + "). ")
TextWindow.WriteLine("The total is " + outcome)
Although your outcome will be a number between 2 (rolling two 1s) and 12 (rolling two 6s), don’t make the mistake of writing this:
outcome = 1 + Math.GetRandomNumber(11)
Although this statement gives you a number between 2 and 12, the probability you’d get from one random number is different from adding two random numbers together.
TRY IT OUT 7-5
A bag contains 20 balls numbered from 1 to 20. Write a program that simulates drawing one ball from the bag at random.
Trigonometric functions are those mischievous enemies of high school students (sine, cosine, tangent, and so on). We won’t explain what these are, but if you have no idea what a trigonometric function is or you’ve never even heard the word trigonometry, don’t worry. Just skip ahead toChapter 8. Otherwise, let’s jump right in with an example.
Imagine that androids from the future have traveled back to our time to destroy humanity, and you’re the only person who can stop their attack. You’ll need to use your cannon to destroy their weapons warehouse, as shown in Figure 7-3.
Figure 7-3: Destroying the androids’ warehouse
Your cannon fires with an initial speed, v, of 160 feet per second. The warehouse is 500 feet away. All you have to do is figure out the launch angle θ (the Greek letter theta). The program in Listing 7-4 prompts you to enter the desired angle, and then it computes the missile range d (in feet) according to the formula shown in the figure.
You need to run the program several times (using different launch angles) to find the best angle for your shot.
1 ' AndroidAttack.sb
2 v = 160 ' Initial speed = 160 feet/sec
4 TextWindow.WriteLine("Shoot the cannon to destroy the warehouse!")
5 TextWindow.Write("Enter launch angle in degrees: ")
6 angle = TextWindow.ReadNumber()
7 theta = Math.GetRadians(angle) ' Angle in radians
9 d = (v * v) * Math.Sin(2 * theta) / 32
10 d = Math.Round(d) ' Rounds to the nearest integer
12 TextWindow.WriteLine("Distance = " + d + " feet.")
Listing 7-4: Finding the launch angle
After the prompt, the program reads your input and saves it in the variable angle (line 6). Then line 7 converts the angle from degrees to radians using the GetRadians() method (the Sin() method requires its input to be given in radians).
After that, the program computes the distance using the given formula (line 9), rounds it to the nearest integer (line 10), and displays it (line 12).
Here’s a sample run:
Shoot the cannon to destroy the warehouse!
Enter launch angle in degrees: 45
Distance = 800 feet.
It looks like humanity isn’t quite safe yet. Enter some different angles in the program until you get it right.
In addition to the Sin() method, the Math object also provides Cos(), Tan(), ArcSin(), ArcCos(), and ArcTan(). You can read more about these methods in the Additional Resources section for this chapter at http://www.nostarch.com/smallbasic/.
TRY IT OUT 7-6
You want to select a 20-foot Christmas tree (for your school’s festival) from a forest. One way to find the right tree is to attach a tape measure to a monkey and have it climb each tree, but let’s use a little trigonometry instead. If you measure the distance, d, from the base of the tree and the angle, θ, as shown in Figure 7-4, you can compute the height of the tree, h, like this:
h = d tan(θ)
Write a program that lets you enter d and θ, and computes the height of the tree.
Figure 7-4: Computing the height of a tree
If you get stuck, check out http://nostarch.com/smallbasic/ for the solutions and for more resources and review questions for teachers and students.
1. Write a Small Basic statement for each of these algebraic expressions:
b. a = x(yz)
2. The following puzzle was written by the Egyptian scribe Ahmes in 1650 BCE.
“Seven houses each have seven cats. Each cat kills seven mice. Each mouse, if alive, would’ve eaten seven ears of grain. Each ear of grain would have produced seven bushels of wheat. How many bushels of wheat were saved by the cats?”
Write a Small Basic program to find the answer. (Hint: use the Power() method.)
3. Create a program that converts a number of seconds (input by the user) to the equivalent number of hours, minutes, and seconds. For example, if the user enters 8110 seconds, the program reports 2 hours, 15 minutes, and 10 seconds.