# Extra Functions: math and random¶

In Meaningful Chunks and Modules, we’ll digress to look at the extension libraries. This is because the bulk of the math functions are in a separate module or library, called math. We’ll look at parts of it in The math Module – Trig and Logs. We’ll also look at the random number generators in The random Module – Rolling the Dice.

For those who will be using Python for financial and other fixed-point calculations, we’ll look at fixed-point math, also. However, we’ll defer this until Fixed-Point Numbers : Doing High Finance with decimal because it is a bit more advanced than using the built-in types of numbers.

## Meaningful Chunks and Modules¶

Python’s use of modules is a way to break the solution to a problem down into meaningful chunks. We hinted around about this in Core Coolness. There are dozens of standard Python modules that solve dozens of problems for us. We’re not ready to look at modules in any depth, that comes later in Modules : The unit of software packaging and assembly. This section has just a couple of steps to start using modules so that you can make use of two very simple modules: math and random.

A Python module extends the Python language by adding new classes of objects, new functions and helpful constants. The import statement tells Python to fetch a module, adding that module to our working environment. For now, we’ll use the simplest form: import.

import m


This statement will tell Python to locate the module named m and provide us with the definitions in that module. Only the name of the module, m, is added to the local names that we can use. Every name inside module m must be qualified by the module name. We do this by connecting the module name and the function name with a .. When we import module math, we get a cosine function that we refer to with “module name dot function name” notation: math.cos().

This module qualification has a cost and a benefit. The cost is that you have to type the module name over and over again. The benefit is that your Python statements are explicit and harbor no assumptions. There are some alternatives to this. We’ll cover it when we explore modules in depth.

Another important thing to remember is that you only need to import a module once to tell Python you will be using it. By once, we mean once each time you run the Python program. Each time you exit from the Python program (or turn your computer off, which exits all your programs), everything is forgotten. Next time you run the Python program, you’ll need to provide the import statements to add the modules to Python for your current session.

An Interesting Example. For fun, try this:

import this


The this module is atypical: it doesn’t introduce new object classes or function definitions. Instead, well, you see that it does something instead of extending Python by adding new definitions.

Even though the this module is atypical, you can still see what happens when you use an extra import. What happens when you try to import this a second time?

## The math Module – Trig and Logs¶

The math module defines the common trigonometry and logarithmic functions. It has a few other functions that are handy, like square root. The math module is made available to your programs with:

import math


Since this statement only adds math to the names Python can recognize, you’ll need to use the math prefix to identify the functions which are inside the math module.

Here are a couple of examples of some trigonometry. We’re calculating the cosine of 45, 60 and 90 degrees. You can check these on your calculator. Or, if you’re my age, you can use a slide rule to confirm that these are correct answers.

>>> import math
>>> math.cos( 45 * math.pi/180 )
0.70710678118654757
>>> math.cos( 60 * math.pi/180 )
0.50000000000000011
>>> math.cos( 90 * math.pi/180 )
6.123233995736766e-17
>>> round( math.cos( 90*math.pi/180 ), 3 )
0.0


Tip

Debugging Math Functions

The most common problem when using math functions is leaving off the math to qualify the various functions imported from this module. If you get a “NameError: name 'cos' is not defined” error message, it means you haven’t included the math qualifier.

The next most common problem is forgetting to import math each time you run IDLE or Python. You’ll get a “NameError: name 'math' is not defined” error if you forgot to import math.

The other common problem is failing to convert angles from degrees to radians.

The math module contains the following trigonometric functions. The trig functions all use radians to measure angles. If your problem uses degrees, you’ll have to convert from degrees to radians. If your trigonometry is rusty, remember that radians are 360 degrees.

Here are some trig function definitions. We don’t provide all of them, because they’re on the Python web site. See http://docs.python.org/library/math.html for the complete list of available functions.

### Trigonometry Function Definitions¶

math.asin(x) → number

Returns the arc sine of x.

math.atan(x) → number

Returns the arc tangent of x.

math.atan2(y, x) → number

Returns the arc tangent of y / x.

math.cos(x) → number

Returns the cosine of x radians.

math.sin(x) → number

Returns the sine of x radians.

math.tan(x) → number

Returns the tangent of x radians.

Additionally, the following constants are also provided.

pi: The value of , 3.1415926535897931 The value of e, 2.7182818284590451, used for the exp() and log() functions.

Here’s an example of using some of these more advanced math functions. Here is a trig identity for the cosine of 39 degrees. We use 39*math.pi/180 to convert from degrees to radians. We also use the square root function (sqrt()).

>>> import math
>>> math.sqrt( 1-math.sin(39*math.pi/180)**2 )
0.77714596145697101
>>> math.cos( 39*math.pi/180 )
0.7771459614569709


Here are some more of these common trigonometric functions, including logarithms, anti-logarithms and square root.

>>> math.exp( math.log(10.0) / 2 )
3.1622776601683795
>>> math.exp( math.log(10.0) / 2 )
3.1622776601683795
>>> math.sqrt( 10.0 )
3.1622776601683795


Logarithm Function Definitions.

math.exp(x) → number

Returns math.e**x (), inverse of log().

math.hypo(x) → number

Returns the Euclidean distance, sqrt( x*x + y*y ) (), length of the hypotenuse of a right triangle with height of y and length of x.

math.log(x) → number

Returns the natural logarithm (base e) of x (), inverse of exp().

math.log10(x) → number

Returns the logarithm (base 10) of x (), inverse of .

math.pow(x, y) → number

Returns x**y ().

math.sqrt(x) → number

Returns the square root of x (). This version returns an error if you ask for sqrt(-1), even though Python understands complex and imaginary numbers.

A second module, cmath, includes a version of sqrt() which creates imaginary numbers as needed.

## More math Functions¶

The following batch of functions supplement the basic round() function with more sophisticated computations on floating-point numbers. You can probably guess from the names what ceiling and floor mean.

>>> math.ceil(2.1)
3.0
>>> math.floor(2.999)
2.0


The math module contains the following other functions for dealing with floating-point numbers.

Other Floating-Point Function Definitions.

math.ceil(x) → number

Returns the next larger whole number. math.ceil(5.1) == 6, math.ceil(-5.1) == -5.0.

math.fabs(x) → number

Returns the absolute value of the x as a floating-point number.

math.floor(x) → number

Returns the next smaller whole number. math.floor(5.9) == 5, math.floor(-5.9) == -6.0.

## Misuse and Abuse¶

Some of the math functions only work for a limited domain of values. Specifically, square root is only defined for non-negative numbers and logarithms are only defined for positive numbers. What does Python do when we violate these rules?

Try the following expressions:

math.sqrt(-1)
math.log(-1)
math.log(0)


You’ll see one of two kinds of results. The details vary among the operating systems.

• You’ll see a result of nan. This is a special code that means Not a Number.
• You’ll see an exception, like ValueError or OverflowError. An exception will display a bunch of debugging information that ends with the exception name and a short explanation.

Both results amount to the same thing: the result cannot be computed.

## The random Module – Rolling the Dice¶

The random module defines functions that simulate random events. This includes coin tosses, die rolls and the spins of a Roulette wheel. The random module is made available to your program with:

import random


Since this statement only adds random to the names Python can recognize, you’ll need to use the random prefix on each of the functions in this section.

The randrange() is a particularly flexible way to generate a random number in a given range. Here’s an example of some of the alternatives. Since the answers are random, your answers may be different from these example answers. This shows a few of many techniques available to generate random data samples in particular ranges.

>>> import random
>>> random.randrange(6)
5
>>> random.randrange(1,7)
6
>>> random.randrange(2,37,2)
6
>>> random.randrange(1,36,2)
13

1. We’re asking for a random number, n, such that . The number will be between 0 and 5, inclusive.
2. We’re asking for a random number, n, such that . The number will be between 1 and 6, inclusive.
3. We’re asking for a random even number, n, such that . The range function is defined by start, stop and step values. When the step is 2, then the values used are .
4. We’re asking for a random odd number, n, such that . The number will be between 1 and 35, inclusive. Here, we start from 1 with a step of 2; the values used are .

The random module contains the following functions for working with simple distributions of random numbers. There are several more sophisticated distributions available for more complex kinds of simulations. Casino games only require these functions.

## Random Function Definitions¶

random.choice(sequence) → value

Chooses a random value from the sequence sequence. Example: random.choice( ['red', 'black', 'green'] ).

random.random() → number

Creates a random floating-point number, r , such that . Note that random() doesn’t require any arguments, but does require the empty ()s to alert Python that it is really the name of a function. We use it like this: random.random().

random.randrange([start], stop[, step])

Chooses a random element from range( start, stop , step ). We’ll revisit this in Built-in Functions for Lists. For now, we’ll stick with the following examples:

randrange(6) returns a number, n, such that .

randrange(1,7) returns a number, n, such that .

randrange(10,100,5) returns a number, n, between 10 and 95 incremented by 5’s, .

random.uniform(a, b) → number

Creates a random floating-point number, r , such that .

## Extra Function Exercises¶

1. Evaluate These Expressions.

The following expressions are somewhat more complex, and use functions from the math module.

math.sqrt( 40.0/3.0 - math.sqrt(12.0) )

6.0/5.0*( (math.sqrt(5)+1) / 2 )**2

math.log( 2198 ) / math.sqrt( 6 )

2. Tossing a Coin.

There are several ways the random module can be used to simulate tossing a coin. Write expressions that use choice() and randrange().

Additionally, using something like int(random()*X), for some value of X, you can simulate a coin toss. If we use zero for heads and 1 for tails, what is an appropriate value for X? What if we use round() instead of int()? What about ceil() and floor()?

Can you also use uniform() to simulate a coin toss? Do you need to also use int()?

## Function FAQ’s¶

Why do functions have an usual syntax?
Python functions all consistently look a little like the mathematical sin(x). Mathematicians have evolved a number of other forms for functions. Python’s syntax is, at least, consistent. Rather than ask why Python looks the way it does, we prefer to ask why the mathematicians have so many different forms for functions.
Why is math (or random or decimal) a separate module?

There are two reasons for keeping math (or random or decimal) in separate modules.

• Not everyone needs math so why include it needlessly?
• There will always be new implementations of basic numeric algorithms with different trade-offs for range, precision, speed and amount of storage. Rather than pick one, Python leaves it to you to select among the various alternatives and pick that one that best meets your needs.
Everything I do involves math (or random or decimal), why do I have to import it in every single script?
There is one very important reason for importing the module in every single script. It keeps you (and Python) honest: nothing is assumed. You said you needed math, making it clear to everyone else who reads your script. While you know that all your programs are mathematical, almost no one else knows this. The import statement sets the assumptions on a script-by-script basis, making each a successful, stand-alone program, without requiring any insider information or background to understand it.