Chapter 2

Numbers & Math

Subsections of Numbers & Math

Integers

YouTube Video

Resources

So far, we’ve only worked with string values in Python. Strings are a very useful data type in programming languages such as Python, but they are very limited in their use. Recall that a data type simply defines how a particular value is stored in a computer. The str data type is used to store string values in Python.

Python supports many different data types for handling various data that we’d like to store and manipulate in our programs. In this lab, we’re going to cover the two basic types used for storing numbers in Python, the int or integer type, and the float or floating-point type.

Integers

In mathematics, an integer is a whole number, such as $ 3 $, $ -5 $, or even $ 0 $. Basically, any positive or negative number that doesn’t include a fractional or decimal portion is a whole number, and therefore it is an integer. In Python, those numbers can be stored in the int data type.

In Python, we can store an integer value in a variable using an assignment statement:

x = 5

That statement will store the integer value $ 5 $ in the variable x. Notice that the value $ 5 $ does not have quotation marks around it. This is because we want to store the integer value $ 5 $ and not the string value "5" in the variable. Also, as we learned earlier, this is why we cannot create variable names that begin with a number - since numerical values start with a number, this is how Python can tell the difference between a numerical value and a variable.

We can also store negative numbers in a variable by placing a negative symbol - in front of the numerical value:

y = -8

We’ll need to be careful and make sure that there is a space after the equals sign =, but no space between the negative symbol - and the number after it. Otherwise, the negative symbol could be confused for the minus symbol, which is an operator that we’ll learn about later in this lab.

In Python, there is effectively no maximum size for an integer, so we can store any arbitrarily large whole number (either positive or negative) in an int variable.

Subsections of Integers

Floats

YouTube Video

Resources

The other type of number we can store in Python is a floating-point number. We won’t go into too much detail about floating-point values here, since you’ll learn about them elsewhere in this class. For the purposes of programming, the only thing to know about floating-point numbers is that they are used to represent numbers that include a fractional or decimal portion. In Python, these values are stored in the float data type.

To create a variable that stores a floating-point value in Python, we can use an assignment statement that includes a value with a decimal point, like this:

a = 5.8

We can also create negative values using the negative symbol -:

b = -7.987

Finally, it is possible to store a whole number in a floating-point value by simply adding a decimal point and a 0 at the end of the value, as in this example:

c = 42.0

Later in this lab, we’ll see a couple of situations where that may be useful.

For now, we’re just going to assume that Python can easily handle any reasonable number we want it to store in a float variable, but there are some limits to the size and accuracy of those numbers. To reach these limits, we usually have to be dealing with numbers that have $ 100 $ or more digits, either before or after the decimal place. So, for the purposes of this class, those limits really won’t apply to what we’re doing. You’ll learn about these limits in detail in later programming classes.

Subsections of Floats

Types

YouTube Video

Resources

Determining Variable Type

One thing that is very useful to know how to do in Python is determining the type of data stored in a variable. Python is very flexible, and we can store any type of data in any variable. In fact, a variable’s data type can even change in Python, which is something that many other programming languages won’t allow. Technically speaking, we would say that Python uses strong typing, which means that each variable has a known data type that we can find, and dynamic typing, meaning that the type of the variable can change while the program is running.

To determine the type of a variable, we can use the type(expression) function in Python. We can simply place any variable or expression in the expression argument, and then it will tell us the type of the value that results from evaluating that expression. Then, we can simply use the print() function to print it to the screen. We won’t use this in our programs themselves, but it can be helpful for debugging purposes or to just better understand what is going on with data types.

Here’s a quick example program showing the type() function in Python:

x = "Hello"
y = 5
z = 6.7
print(type(x))
print(type(y))
print(type(z))

When we execute this code in Python, we should see the following output:

<class 'str'>
<class 'int'>
<class 'float'>

Based on that output, we can assume that the variable x is the str data type for strings, y is the int data type for whole numbers, and z is the float data type for decimal numbers. The type() function is pretty handy!

Converting Between Data Types

We can also convert values between the various data types in Python. To do this, there are special functions that match the name of the data types themselves. So, to convert any value to a string, we can use the str() function. Likewise, to convert anything to an integer, we can use the int() function. And finally, to convert anything to a floating-point value, we can use the float() function.

So, we can extend the previous example a bit by showing how we can convert values between different data types:

x = "5.7"
print(x)
print(type(x))
print()
y = float(x)
print(y)
print(type(y))
print()
z = int(y)
print(z)
print(type(z))

When we run this program, we’ll get this output:

5.7
<class 'str'>

5.7
<class 'float'>

5
<class 'int'>

In this program, we’re starting with the string value "5.7" stored in variable x. So, the first two print() statements will print that string value, and show that x is indeed storing a str data type. Then, we’ll use the float() function to convert the string value "5.7" stored in x to the floating-point value $ 5.7 $ and store that in y. The next two print statements will print that value, and show that y is storing a float data type. Notice that the value printed for both variables x and y looks identical, but the data type of each variable is different!

Finally, we can use the int() function to convert the floating-point value $ 5.7 $ to an integer. In math, when we are asked to convert the number $ 5.7 $ to a whole number, our first instinct is probably to just round up to $ 6 $, since that is the closest value. However, in Python, as in most other programming languages, this function will simply truncate the value instead. Truncating a value simply means we take off the end of the value, so to convert $ 5.7 $ to an integer we just remove the decimal portion, and we’re left with the value $ 5 $. So, in the output above, we see that z stores the integer value $ 5 $, and it is the int data type.

Notice that we are careful to say that the int() function will truncate the value, and not that it will round down. This is due to how Python handles negative numbers like $ -5.7 $. When converting that to an integer, it will also truncate it to $ -5 $ instead of rounding down to $ -6 $. So, we use the word truncate as the best way to describe the int() function.

Exceptions

Since we are running our Python programs on a real computer, we have to be a bit careful about how we use these functions. Specifically, if we try to convert a value to a different data type and Python can’t figure out how to do that, we’ll cause an exception to occur. An exception in programming is any error that happens when the computer tries to run our code.

For example, what if we try to convert the string value "5.7" directly to an int data type, as in this example:

a = "5.7"
print(a)
print(type(a))
print()
b = int(a)
print(b)
print(type(b))

When we try to run this code in a file, such as the tutor.py file shown here, we’ll see this output printed on the terminal:

5.7
<class 'str'>

Traceback (most recent call last):
  File "tutor.py", line 5, in <module>
    b = int(a)
ValueError: invalid literal for int() with base 10: '5.7'

Uh oh! That’s not good. In the output, we can see that we’ve caused a ValueError, which is an exception that happens when we try to use a value in an incorrect way. So, we’ll need to carefully look at our code to see if we can find and fix the error.

Thankfully, in the output, it will tell us that the error occurred on line 5 of the file tutor.py, so we can open that file and scroll to that line of code:

b = int(a)

This is where the error occurred. There are several ways we can fix it. The easiest would be to simply convert a to a floating-point value using the float() function instead.

Learning how to find and fix these exceptions is a key part of learning how to program. We’ll inevitably run into a few exceptions as we start to build larger and more complex programs. In this course, most exceptions can be easily handled simply by working carefully through the code, but every once in a while we may run into an exception that is truly difficult to solve. That’s one of the important things to remember when learning how to program - it is sometimes much easier to cause an exception than it is to figure out how to fix it, and sometimes you may need to reach out for help to get past a particularly tricky exception. So, don’t be afraid to ask the instructors or TAs for help if you get stuck on an exception. Many times, it’s a great chance for you to learn some new programming skills.

Subsections of Types

Basic Operators

YouTube Video

Resources

Now that we have the ability to store numerical data in variables in Python, we should also learn how to manipulate that data into something new. To do that, let’s learn about operators. An operator in programming is a special symbol that can be used in an expression to manipulate the data in some way.

Most operators are binary operators, which means they perform an operation that uses two values as input and produces a single value as output. In fact, in some programming languages, the operators themselves are implemented as functions in the language! Finally, we have to be careful not to confuse these with bitwise operators, which are operators perform operations on the binary value stored in a variable. We won’t cover those operators in this class, but the terminology is a bit confusing.

An expression containing a binary operator typically follows this format:

<expression> <operator> <expression>

As before, the <expression> parts can be any valid expression in the language that can be reduced to a single value, and the <operator> part is typically a single symbol, but it can also be a short keyword as well.

Thankfully, these operators should all be very familiar to us from mathematics already, so this is just a quick discussion of how they can be used in programming.

Addition and Subtraction

For starters, we can use the plus + and minus - symbols as operators to perform addition and subtraction in Python, just like in math. For example, we can add two variables together to create a third variable as shown in this example:

a = 5
b = 7
c = a + b
print(c)

When we run this code in the Python interpreter, we should get this result:

12

Likewise, we can subtract two variables using the minus symbol - as shown here:

x = 24
y = 10
z = x - y
print(z)

This code should produce this output:

14

Multiplication and Division

In Python, we use the asterisk *, sometimes referred to as the star symbol, to multiply two values together. For example, we can find the product of two values as shown in this Python block:

a = 6
b = 7
c = a * b
print(c)

When we run this code, we should see the following result displayed to the user:

42

Division is performed using the slash / symbol. A great way to think of division in programming is just like a fraction, since it uses the same symbol between the two numbers. For example, if we execute this code:

x = 27
y = 3
z = x / y
print(z)

we would see this output:

9.0

What if the division would result in a remainder? In that case, we’ll simply use decimal values in Python so that the result is exactly correct. For example, if we try to divide $ 19 $ by $ 5 $, as in this example:

a = 19
b = 5
c = a / b
print(c)

When we run this code, the Python interpreter will produce the following output:

3.8

So, as we can see, all of these operators in Python work exactly like their counterparts in math. So, we can easily use them in a way that should be very familiar to us.

Subsections of Basic Operators

New Operators

YouTube Video

Resources

Modulo Operator

The Python programming language also includes a few math operators that are not commonly used outside of programming.

The first one is the modulo operator. The modulo operator is used to find the remainder of a division operation. If we think back to math again, we’ve probably learned how to perform long division when dividing two values. At the end, we might be left with a remainder, or a portion of the first number that is left over after the operation is complete. In many computer programs, that value is very useful, so we have a special operator we can use to find that value. In Python, we use the percent symbol % as the modulo operator.

For example, if we want to find the remainder after dividing $ 19 $ by $ 5 $, we would use the following code:

x = 19
y = 5
z = x % y
print(z)

When we run this code, we would get the following output:

4

This is because the value $ 5 $ will fit into the value $ 19 $ only $ 3 $ times, and then we’ll have the value $ 4 $ left over. Mathematically, we are saying that $ 19 / 5 = (3 * 5) + 4 $. Since $ 4 $ is the leftover portion, it is the resulting value when we use the modulo operator.

In this course, we’ll only worry about how the modulo operator works when applied to positive whole numbers. In practice, it can be applied to any numerical value, including decimal values and negative numbers, but those values are not really useful in most cases. So, to keep things simple, we’ll only use positive whole numbers with this operator.

Exponentiation Operator

The next operator introduced by Python is the exponentiation operator. The double star ** operator is used to represent exponentiation, sometimes referred to the power operator. In Python, the expression 2 ** 3 would be written mathematically as $ 2^3 $, which is the operation of taking $ 2 $ to the power of $ 3 $, or multiplying $ 2 $ by itself $ 3 $ times.

Here’s a quick example of using the ** operator in code:

x = 5 ** 3
print(x)
print(type(x))

When this code is run, we see the following output:

125
<class 'int'>

||| growthhack

Don’t Use the Carat ^!

Many other programming languages and tools use the carat ^ character to represent the exponentiation operation. However, in Python, the carat ^ character is used to represent the bitwise XOR operation. So, we must be careful not to accidentally use the ^ operator when we actually mean to use the ** operator for exponentiation.

|||

Integer Division Operator

Finally, Python also includes the integer division operator, represented by two forward slashes //, which is used to perform division that truncates the result to an integer. However, as we’ll see on the next page, if either of the values in the operation is a float value, it will return a value that is a float data type, even though the result is an integer value.

Let’s look at an example with that operator in code:

a = 17.5 // 4.5
print(a)
print(type(a))

As we expect, when we run this program, we’ll get the following output:

3.0
<class 'float'>

So, we see that this operator will return a float value, even though it is truncating the result to an integer, simply because the input values contained a float.

Subsections of New Operators

Resulting Types

YouTube Video

Resources

Since Python has multiple numeric data types, there are some rules that govern which data type is produced as a result of various math operations. Thankfully, the rules themselves are pretty straightforward once they are explained.

Resulting Data Types - Same Type

The basic rule to remember, if a mathematical operator is applied to two variables of the same data type, the result will also be that data type.

Let’s see what that means in practice. Here’s a quick example in Python using the multiplication operator on two integer values:

x = 5
y = 10
z = x * y
print(z)
print(type(z))

When we run this code, we should see the following output:

50
<class 'int'>

Since both x and y are the int data type, the result of x * y will also be an int value, so the variable z will have that data type, as shown in this example.

However, there is one exception to this rule, which is the division operator /. In Python, the division operator will always return a float value, even if it is a whole number. Here’s an example that demonstrates that:

a = 9
b = 3
c = 4
x = a / b
print(x)
print(type(x))
print()
y = a / c
print(y)
print(type(y))

When we run this program, we’ll see the following output:

3.0
<class 'float'>

2.25
<class 'float'>

So, as we can see, even though we are dividing two int values, we’ll get a float value as a result each time we use the division operator.

Following the rule above, if we perform a mathematical operation between two float values, the resulting value will always be a float as well:

a = 2.5
b = 4.5
c = a + b
print(c)
print(type(c))

Running this code will produce this output:

7.0
<class 'float'>

So, even though the result is a whole number, the value that is stored is the float data type.

Resulting Data Types - Different Type

The other rule to remember is anytime an operation involves a float value and an int value, the result will be a float. So, if there are mixed types, Python will default to the float data type.

This can be seen in the following example:

a = 5
b = 2.0
c = a - b
print(c)
print(type(c))

When this code is executed, the output should look like this:

3.0
<class 'float'>

Once again, even though the result is a whole number, because the variable b is a float value, the entire result will also be a float value.

Learning the data types that are returned by a mathematical operator can be tricky, but most programmers slowly develop an intuition of how each operator works and what to expect. So, don’t worry too much if this is confusing right now, since it will become much clearer with practice! Also, don’t forget that we can always create a simple test program like the examples shown above to confirm the result for any operation.

Subsections of Resulting Types

Order of Operations

YouTube Video

Resources

Finally, just like in mathematics, we must also be aware of the order that these operators are applied, especially if they are combined into a single expression. Thankfully, the same rules we learned in mathematics apply in programming as well. Specifically, operators in Python are applied in this order:

  1. Operations in parentheses are resolved first, moving from left to right.
  2. ** is resolved second, moving from left to right
  3. *, /, // and % are resolved third, moving from left to right.
  4. + and - are resolved fourth, moving from left to right.

You might recall the “PEMDAS” acronym for remembering the order of operations in math, and thankfully it still applies here. Of course, this means that there are now 4 operators that all fit in the “multiplication and division” portion, so we have to carefully make sure they are all taken care of in the correct way.

Also, as you’ve probably already learned in math, it is always best to add extra parentheses to any expression to make the intent very clear instead of relying on the order of operations. So, when in doubt, use extra parentheses wherever needed!

Let’s work through a quick example just to see the order of operations in practice. Here’s a complex expression in Python that we can try to evaluate:

x = 8 / 4 + 5 * (3 + 1) - 7 % 4

Looking at our order of operations, the first step is to handle any expressions inside of parentheses. So, we’ll first start with the expression (3 + 1) and evaluate it to 4.

x = 8 / 4 + 5 * 4 - 7 % 4

Then, we’ll go left to right and perform any multiplication, division, and modulo operations. This means we’ll evaluate 8 / 4, 5 * 4 and 7 % 4 and replace them with the resulting values:

x = 2.0 + 20 - 3

Notice that 8 / 4 was reduced to 2.0 instead of just 2. This is because the division operator is the one exception to the rule where an operator applied to two integers will result in an integer. The division operator always produces a floating-point value.

Finally, we’ll perform addition and subtraction from left to right. So, we’ll evaluate 2.0 + 20 first, and then subtract 3 from the result of that operation. At the end, we’ll have this statement:

x = 19.0

So, we were able to use our knowledge of the order of operations to evaluate that complex expression to a single value, $ 19.0 $, which will be stored in the variable x.

Subsections of Order of Operations

Math Practice

Let’s try some simple practice problems. These problems are not graded - they are just for you to practice before doing the real exercises in the lab itself. You can find the answers below each question by clicking the button below each question.

2.1 Reading Code

Write the output that is displayed to the user after running the following Python code:

x = 13
z = "5"
y = int(z)
var = (x + y) % y * y - x
var = var / 2
print(var)

Pay special attention to data types! Make sure the answer is presented as the correct type.

2.1 Answer

The correct answer is

1.0

Following order of operations, we do parentheses first:

(x + y) % y * y - x
(13 + 5) % 5 * 5 - 13
18 % 5 * 5 - 13

Then we will do multiplication and modulo left to right. Recall that % is the modulo operation, so 18 % 5 is the remainder of 18 / 5, which is 3:

18 % 5 * 5 - 13
3 * 5 - 13
15 - 13

Finally, we do subtraction:

15 - 13
2

The last line will compute 2 / 2, which is just 1.0. Recall that the division operation always produces a float, not an integer.

2.2 Reading Code

Write the output that is displayed to the user after running the following Python code:

x = 9
y = 3.0
z = 5
ans = (x - z) % 2 // y + z ** (y - 1)
print(ans)

Pay special attention to data types! Make sure the answer is presented as the correct type.

2.2 Answer

The correct answer is:

25.0

Following order of operations, we do parentheses first:

(x - z) % 2 // y + z ** (y - 1)
(9 - 5) % 2 // 3.0 + 5 ** (3.0 - 1)
4 % 2 // 3.0 + 5 ** 2.0

Then, we’ll perform all multiplication, division, modulo, and integer division from left to right:

4 % 2 // 3.0 + 5 ** 2.0
0 // 3.0 + 5 ** 2.0
0.0 + 5 ** 2.0
0.0 + 25.0

Finally, we’ll perform addition to find the answer of 25.0.

2.3 Writing Code

You are teaching a class and would like to put your students into a number of groups. You know how many students are in the class and the number of groups to create, but you aren’t sure how many students should be in each group.

We’ll assume that these values are stored in the students and groups variables, respectively.

Write a Python program to compute the ideal group size for each group in the class. When divided, the groups in the class should have no fewer than size people, and no more than size+1 people, and there should be exactly groups groups total. For example, if there are $ 15 $ people and the desired number of groups is $ 4 $, then code should start with the following two variable assignments.

students = 15
groups = 4

# more code goes here

Your code should produce the following output for these values:

groups of 3 or 4

This is because the ideal group size for $ 4 $ groups out of $ 15 $ people is $ 3 $, and all groups should have either $ 3 $ or $ 4 $ members (in this case, one group of $ 3 $ and the rest groups of $ 4 $).

Write the rest of this Python program. Try different values for the students and groups variables to make sure that your answers are correct!

2.3 Answer

One possible answer:

students = 15
groups = 4

# more code goes here
size = students // groups
print("groups of ", end="")
print(size, end="")
print(" or ", end="")
size = size + 1
print(size)

The values in the students and groups variables can be changed. The key is to use the integer division operator to determine the size of each group, though some groups may have 1 more member if there is a remainder. You can even use the modulo operator to determine how many groups will get an extra member!

Summary

In this lab, we covered several major important topics. Let’s quickly review them.

Data Types in Python

  • str data type stores text (strings). Use str(expression) to convert an expression to a string if possible.
  • int data type stores whole numbers (integers). Use int(expression) to convert an expression to an integer if possible.
  • float data type stored decimal numbers (floating-point). Use float(expression) to convert an expression to a floating-point value, if possible.

Math Operators in Python

  • + Addition
  • - Subtraction
  • * Multiplication
  • ** Exponentiation (Power)
  • / Division
  • // Integer Division
  • % Modulo (the remainder of division)

Python Order of operations

  1. Parentheses
  2. Exponentiation
  3. Multiplication, Division, Integer Division, and Modulo from left to right
  4. Addition and Subtraction from left to right