The math and random Modules, Bit-Level Operations, Division
Division Operators covers the important distinction between the division operators. We also provide some supplemental information that is more specialized. Bit Manipulation Operators covers some additional bit-fiddling operators that work on the basic numeric types. Expression Style Notes has some notes on style.
A Python module extends the Python execution environment by adding new classes, functions and helpful constants. We tell the Python interpreter to fetch a module with a variation on the import statement. There are several variations on import, which we’ll cover in depth in Components, Modules and Packages.
For now, we’ll use the simple import:
This will import module m. Only the module’s name, m is made available. Every name inside the module m must be qualified by prepending the module name and a .. So if module m had a function called spam(), we’d refer to it as m.spam().
There are dozens of standard Python modules. We’ll get to the most important ones in Components, Modules and Packages. For now, we’ll focus on extending the math capabilities of the basic expressions we’ve looked so far.
The math module is made available to your programs with:
The math module contains a number of common trigonometric functions.
Additionally, the following constants are also provided.
|math.pi:||the value of , 3.1415926535897931|
|math.e:||the value of e, 2.7182818284590451, used for the exp() and log() functions.|
Conversion between radians, r, and degrees, d, is based on the following definition:
From that, we get the following relationships:
The math module contains the following other functions for dealing with floating point numbers.
Next larger whole number.
>>> import math >>> math.ceil(5.1) 6.0 >>> math.ceil(-5.1) -5.0
Next smaller whole number.
>>> import math >>> math.floor(5.9) 5.0 >>> math.floor(-5.9) -6.0
Floating point remainder after division of . This depends on the platform C library and may handle the signs differently than the Python x % y.
>>> math.fmod( -22, 7 ) -1.0 >>> -22 % 7 6
Creates a tuple with the fractional and integer parts of x. Both results carry the sign of x so that x can be reconstructed by adding them. We’ll return to tuples in Tuples.
>>> math.modf( 123.456 ) (0.45600000000000307, 123.0)
The random module contains a large number of functions for working with distributions of random numbers. There are numerous functions available, but the later exercises will only use these functions.
The random module is made available to your program with:
Here are the definitions of some commonly-used functions.
Chooses a random value from the sequence sequence.
>>> import random >>> random.choice( ['red', 'black', 'green'] ) 'red'
Choose a random element from range( start, stop, step ).
The randrange() has two optional values, making it particularly flexible. Here’s an example of some of the alternatives.
#!/usr/bin/env python import random # Simple Range 0 <= r < 6 print random.randrange(6), random.randrange(6) # More complex range 1 <= r < 7 print random.randrange(1,7), random.randrange(1,7) # Really complex range of even numbers between 2 and 36 print random.randrange(2,37,2) # Odd numbers from 1 to 35 print random.randrange(1,36,2)
This demonstrates a number of ways of generating random numbers. It uses the basic random.randrange() with a variety of different kinds of arguments.
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 )
Run demorandom.py. Run the demorandom.py script several times and save the results. Then add the following statement to the script and run it again several times. What happens when we set an explicit seed?
#!/usr/bin/env python import random random.seed(1) ...everything else the same
Try the following variation, and see what it does.
#!/usr/bin/env python import random, time random.seed(time.clock()) ...everything else the same
Wind Chill. Wind chill is used by meteorologists to describe the effect of cold and wind combined.
Given the wind speed in miles per hour, V, and the temperature in °F, T, the Wind Chill, w, is given by the formula below.
Wind Chill, new model
Wind Chill, old model
Wind speeds are for 0 to 40 mph, above 40, the difference in wind speed doesn’t have much practical impact on how cold you feel.
Write a print statement to compute the wind chill felt when it is -2 °F and the wind is blowing 15 miles per hour.
How Much Does The Atmosphere Weigh? Part 1 From Slicing Pizzas, Racing Turtles, and Further Adventures in Applied Mathematics, [Banks02].
Pressure is measured in Newtons, N, . Air Pressure is is measured in Newtons of force per square meter, .
Air Pressure (at sea level) . This is the long-term average.
Acceleration is measured in . Gravity acceleration (at sea level) g.
We can use g to get the kg of mass from the force of air pressure . Apply the acceleration of gravity (in ) to the air pressure (in ). This result is mass of the atmosphere in kilograms per square meter ().
Given the mass of air per square meter, we need to know how many square meters of surface to apply this mass to.
Radius of Earth R in meters, m. This is an average radius; our planet isn’t a perfect sphere.
The area of a Sphere.
Mass of atmosphere (in Kg) is the weight per square meter, times the number of square meters.
Check: somewhere around kg.
How Much Does The Atmosphere Weigh? Part 2. From Slicing Pizzas, Racing Turtles, and Further Adventures in Applied Mathematics, [Banks02].
The exercise How Much Does the Atmosphere Weigh, Part 1 assumes the earth to be an entirely flat sphere. The averge height of the land is actually 840m. We can use the ideal gas law to compute the pressure at this elevation and refine the number a little further.
Pressure at a given elevation
Molecular weight of air .
Gas constant R, in .
Gravity g, in .
Temperature T, in °K based on temperature C, in °C. We’ll just assume that C is 15 °C.
Elevation z, in meters, m.
This pressure can be used for the air over land, and the pressure computed in How Much Does the Atmosphere Weigh, Part 1 can be used for the air over the oceans. How much land has this reduced pressure? Reference material gives the following areas in , square meters.
Weight of Atmosphere, adjusted for land elevation
We’ve already seen the usual math operators: +, -, *, /, %, **; as well as the abs() and pow() functions. There are several other operators available to us. Principally, these are for manipulating the individual bits of an integer value.
We’ll look at ~, &, ^, |, << and >>.
The unary ~ operator flops all the bits in a plain or long integer. 1’s become 0’s and 0’s become 1’s. Since most hardware uses a technique called 2’s complement, this is mathematically equivalent to adding 1 and switching the number’s sign.
>>> print ~0x12345678 -305419897
There are binary bit manipulation operators, also. These perform simple Boolean operations on all bits of the integer at once.
The binary & operator returns a 1-bit if the two input bits are both 1.
>>> print 0&0, 1&0, 1&1, 0&1 0 0 1 0
Here’s the same kind of example, combining sequences of bits. This takes a bit of conversion to base 2 to understand what’s going on.
>>> print 3&5 1
The number 3, in base 2, is 0011. The number 5 is 0101. Let’s match up the bits from left to right:
0 0 1 1 & 0 1 0 1 ------- 0 0 0 1
The binary ^ operator returns a 1-bit if one of the two inputs are 1 but not both. This is sometimes called the exclusive or.
>>> print 3^5 6
Let’s look at the individual bits
0 0 1 1 ^ 0 1 0 1 ------- 0 1 1 0
Which is the binary representation of the number 6.
The binary | operator returns a 1-bit if either of the two inputs is 1. This is sometimes called the inclusive or. Sometimes this is written and/or.
>>> print 3|5 7
Let’s look at the individual bits.
0 0 1 1 | 0 1 0 1 ------- 0 1 1 1
Which is the binary representation of the number 7.
There are also bit shifting operations. These are mathematically equivalent to multiplying and dividing by powers of two. Often, machine hardware can execute these operations faster than the equivalent multiply or divide.
The << is the left-shift operator. The left argument is the bit pattern to be shifted, the right argument is the number of bits.
>>> print 0xA << 2 40
0xA is hexadecimal; the bits are 1-0-1-0. This is 10 in decimal. When we shift this two bits to the left, it’s like multiplying by 4. We get bits of 1-0-1-0-0-0. This is 40 in decimal.
The >> is the right-shift operator. The left argument is the bit pattern to be shifted, the right argument is the number of bits. Python always behaves as though it is running on a 2’s complement computer. The left-most bit is always the sign bit, so sign bits are shifted in.
>>> print 80 >> 3 10
The number 80, with bits of 1-0-1-0-0-0-0, shifted right 3 bits, yields bits of 1-0-1-0, which is 10 in decimal.
There are some other operators available, but, strictly speaking, they’re not arithmetic operators, they’re logic operations. We’ll return to them in Truth, Comparison and Conditional Processing.
In general, the data type of an expresion depends on the types of the arguments. This rule meets our expectations for most operators: when we add two integers, the result should be an integer. However, this doesn’t work out well for division because there are two different expectations. Sometimes we expect division to create precise answers, usually the floating-point equivalents of fractions. Other times, we want a rounded-down integer result.
The classical Python definition of / followed the pattern for other operators: the results depend entirely on the arguments. 685/252 was 2 because both arguments where integers. However, 685./252. was 2.7182539682539684 because the arguments were floating point.
This definition often caused problems for applications where data types were used that the author hadn’t expected. For example, a simple program doing Celsius to Fahrenheit conversions will produce different answers depending on the input. If one user provides 18 and another provides 18.0, the answers were different, even though all of the inputs all had the equal numeric values.
>>> 18*9/5+32 64 >>> 18.0*9/5+32 64.400000000000006 >>> 18 == 18.0 True
This unexpected inaccuracy was generally due to the casual use of integers where floating-point numbers were more appropriate. (This can also occur using integers where complex numbers were implictly expected.) An explicit conversion function (like float()) can help prevent this. The idea, however, is for Python be a simple and sparse language, without a dense clutter of conversions to cover the rare case of an unexpected data type.
Starting with Python 2.2, a new division operator was added to clarify what is required. There are two division operators: / and //. The / operator should return floating-point results; the // operator will always return rounded-down results.
In Python 2.5 and 2.6, the / operator can either use “classical” or “old” rules (results depend on the values) or it can use the “new” rule (result is floating-point.) In Python 3.x, this transitional meaning of / goes away and it always produces a floating-point result.
In Python 3, the / operator will always produces a floating-point result. The // operator will continue to produce an integer result.
To help with the transition, two tools were made available. This gives programmers a way to keep older applications running; it also gives them a way to explicitly declare that their program uses the newer operator definition. There are two parts to this: a program statememt that can be placed in a program, as well as command-line options that can be used when starting the Python interpreter.
Program Statements. To ease the transition from older to newer language features, there is a __future__ module available. This module includes a division definition that changes the definition of the / operator from classical to future. You can include the following import statement to state that your program depends on the future definition of division. We’ll look at the import statement in depth in Components, Modules and Packages.
from __future__ import division print 18*9/5+32 print 18*9//5+32
This produces the following output. The first line shows the new use of the / operator to produce floating point results, even if both arguments are integers. The second line shows the // operator, which produces rounded-down results.
The from __future__ statement will set the expectation that your script uses the new-style floating-point division operator. This allows you to start writing programs with version 2.6 that will work correctly with all future versions. By version 3.0, this import statement will no longer be necessary, and these will have to be removed from the few modules that used them.
Command Line Options. Another tool to ease the transition are command-line options used when running the Python interpreter. This can force old-style interpretation of the / operator or to warn about old-style use of the / operator between integers. It can also force new-style use of the / operator and report on all potentially incorrect uses of the / operator.
The Python interpreter command-line option of -Q will force the / operator to be treated classically (“old”), or with the future (“new”) semantics. If you run Python with -Qold , the / operator’s result depends on the arguments. If you run Python with -Qnew, the / operator’s result will be floating point. In either case, the // operator returns a rounded-down integer result.
You can use -Qold to force old modules and programs to work with version 2.2 and higher. When Python 3.0 is released, however, this transition will no longer be supported; by that time you should have fixed your programs and modules.
To make fixing easier, the -Q command-line option can take two other values: warn and warnall . If you use -Qwarn, then the / operator applied to integer arguments will generate a run-time warning. This will allow you to find and fix situations where the // operator might be more appropriate. If you use -Qwarnall, then all instances of the / operator generate a warning; this will give you a close look at your programs.
You can include the command line option when you run the Python interpreter. For Linux and MacOS users, you can also put this on the #! line at the beginning of your script file.