Numeric Types¶
Indices and tables¶
Definition¶
Python provides 4 first-class types for dealing with numbers.
Integer¶
MUTABILITY: Immutable
In Python, the size of an integer is only limited by available memory. Negative integer values are represented in 2’s complement. Python provides a rich set of methods to create integer values:
Simple base-10 literals can be created as follows:
>>> foo = 1234
>>> foo
1234
Binary, octal and hex literals can be created using the appropriate prefix (0b
, 0o
and 0x
):
>>> foo = 0b11001
>>> foo
25
>>> foo = 0o173
>>> foo
123
>>> foo = 0x1F4
>>> foo
500
Negative literal values can be created just by appending a -
:
>>> foo = -1234
>>> foo
-1234
>>> foo = -0b11001
>>> foo
-25
>>> foo = -0o173
>>> foo
-123
>>> foo = -0x1F4
-500
Note
Python doesn’t display in 2’s complement for negative numbers. This is because integers have arbitrary precision and showing the sign bit of a 2’s complement number would be an infinitely long string of 1s (well, until its memory was exhausted).
Just to prove Python is actually using 2’s complement for negative numbers, we can do a little test using the 1’s complement (invert) operator ~
:
>>> foo = -0b11001
>>> foo
-25 # 0b100111 in 2's complement notation
>>> ~foo
24 # 0b011000
See, no one was lying to you :)
Integer values can also be made using the int
constructor which has the following signature:
-
int
(x[, baseN])¶ Parameters: - x – The value to convert (coerce) to an integer. Optional sign bit. Valid digits are 0-9, A-Z (digits must be valid for the radix chosen by baseN).
- base – The radix of ‘x’. Can be from 2 to 36. Defaults to base-10.
This is commonly used when creating an integer from a string or float (as a type conversion function), or when using a non-standard base. For example:
>>> foo = int('23')
>>> foo
23
>>> foo = int(141.5)
>>> foo
141
>>> foo = int('-Z5', 36)
>>> foo
-1265
>>> foo = int('0b11', 2)
>>> foo
3
>>> foo = int('0o174', 8)
>>> foo
124
>>> foo = int('0xDEADBEAF', 16)
>>> foo
3735928495
The bin()
, oct()
and hex()
functions can be used to convert from an integer to a binary, octal and hexadecimal string, respectively. For example:
>>> foo = bin(5025124513)
>>> foo
'0b100101011100001010101000010100001'
>>> foo = bin(-5025124513)
>>> foo
>>>
'-0b100101011100001010101000010100001'
>>> foo = oct(5025124513)
>>> foo
'0o45341250241'
>>> foo = oct(-5025124513)
>>> foo
'-0o45341250241'
>>> foo = hex(5025124513)
>>> foo
'0x12b8550a1'
>>> foo = hex(-5025124513)
>>> foo
'-0x12b8550a1'
You can get the number of bits required to represent an integer value using bit_length()
. For example:
>>> foo = 0x5025124513
>>> foo.bit_length()
39
If required, you can convert integer objects to/from byte arrays using the int.to_bytes()
and int.from_bytes()
functions which have the following signatures:
-
int.
to_bytes
(length, byteorder, *, signed=False)¶ Parameters: - length – The number of bytes to use to represent the integer.
- byteorder – The endianness. One of ‘big’ or ‘little’.
- signed – If True, 2s-complement is used to represent the integer.
-
classmethod
int.
from_bytes
(bytes, byteorder, *, signed=False)¶ Parameters: - bytes – The array of bytes to convert to an integer.
- byteorder – The endianness. One of ‘big’ or ‘little’.
- signed – If True, 2s-complement is used to represent the integer.
An example will help visualize their use:
>>> foo = 255
>>> foo.to_bytes(4, 'big')
b'\x00\x00\x00\xff'
>>> foo.to_bytes(4, 'little')
b'\xff\x00\x00\x00'
>>> foo = b'\xff\x00\x00\x00'
>>> int.from_bytes(foo, 'little')
4278190080
>>> int.from_bytes(foo, 'little', signed=True)
-16777216
Boolean¶
MUTABILITY: Immutable
Python defines 2 objects, that can be used to indicate truthness, True
and False
. Like None
, there is only one object that has each of these values.
Anywhere you can use use True
and False
, you can also use 1 and 0 for, respectivly. However, you really should use the True
and False
objects when a boolean is required (for one, it’s easier to read).
Python lets you convert other values to booleans to test their truthness using the bool()
function. Specifically, the following values are considered false:
None
False
- zero for any numeric type (ints, floats, complex)
- an empty sequence (strings, tuples, lists)
- an empty mapping (dictionaries)
- instance of user-defined classes that has
__bool__()
or__len__()
defined and it returns 0 orFalse
.
That can be a handy way to test for an empty sequence or mapping. For example:
>>> bool('')
False
>>> bool('Hello World')
True
>>> bool([])
False
>>> bool([1])
True
Float¶
MUTABILITY: Immutable
Python implements double-precision floating points numbers. There is no support for single-precision numbers because the speed-up in using single-precision is much less than the overhead of using objects so there is no advantage.
The sys
package contains a function for learning about float objects in the Python implementation you are using:
>>> import sys
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
You can call help(sys.float_info)
for details on the meaning of each attribute.
One attribute of note is epsilon, which gives the smallest difference between 2 floating point numbers that can be represented.
If you need even greater precision that what is afforded with floats, decimal.Decimal
provides even greater, user-selectable precision (defaulting to 28 decimal places) at the cost of being slower. However, this package will not be covered in this course.
Float literals can be constructed from numbers using a decimal point and/or an exponent:
>>> foo = 1.41
>>> foo
1.41
>>> foo = -294.1351
>>> foo
-294.1351
>>> foo = 6.67408e-11
>>> foo
6.67408e-11
>>> foo = 3E20
>>> foo
3e20
Note
It is the decimal point that makes it a float. Otherwise, Python will treat it as an integer.
Using the float
constructor, you can create floats from strings (as a type conversion function), numbers and the special values of infinity ('inf'
and 'infinity'
) and not-a-number ('nan'
):
>>> foo = float(3.1415)
>>> foo
3.1415
>>> foo = float('-1.7E40')
>>> foo
-1.7e+40
>>> foo = float('inf')
>>> foo
inf
>>> foo = float('-inf')
>>> foo
-inf
>>> foo = float('nan')
>>> foo
nan
Note
The strings 'inf'
, 'infinity'
and 'nan'
, when fed to the float
constructor are not case sensitive. However, when printed they are always their short, lower-case versions.
If you try and create a float value outside what can be represented, you will get a OverflowError
exception.
Like integers, floats have a few more tricks up their sleeves.
You can convert a floating point number to a pair of integers where the ratio between the integers is exactly the same as the floating point value:
>>> float.as_integer_ratio(234.5)
(469, 2)
>>> float.as_integer_ratio(141.13)
(2485775888075981, 17592186044416)
You can test whether a float is a finite integral value:
>>> float.is_integer(4.0)
True
>>> float.is_integer(4.1)
False
Finally, you can move back and forth between hexadecimal string presentation and base-10 representation using the float.hex()
and float.fromhex()
functions:
>>> float.hex(1.25)
'0x1.4000000000000p+0'
>>> float.fromhex('0xA.84p+0')
Note
In hex notation, the exponent is specified using ‘p’, since ‘e’ is a valid hex character.
Complex¶
MUTABILITY: Immutable
Python implements complex numbers as a container that holds a pair of floats; one for the real part and the other for the imaginary part. The real and imaginary parts are separated by a +/-1j.
Complex literals can be constructed from numbers in a couple of ways. For example:
>>> foo = 100 + 10j
>>> foo
(100+10j)
>>> foo = 1.4831 - 9.5213j
>>> foo
(1.4831-9.5213j)
If you want to create a complex number with an imaginary value of 0, you can’t exclude the imaginary component or you will accidentally create an integer or a float. There are 2 ways to solve this problem, the first being set the imaginary component 0j:
>>> foo = 75 + 0j
>>> foo
(75+0j)
Or, use the complex
constructor, which also acts like a type conversion function, and has the following syntax:
-
complex
([real [, [imag]]) Parameters: - real – The real part of the complex number. Can be a numerical value or string. If a string, can also include the imaginary part. If not included, defaults to 0.
- image – The imaginary part of the number. Must be a numerical value. If not included, defaults to 0.
For example:
>>> foo = complex(75)
>>> foo
(75+0j)
>>> foo = complex("23-88.3j")
>>> foo
(23-88.3j)
Warning
The string format does not support whitespace around the sign.
The real and imaginary parts of a complex number can be extracted using the real
and imag
attributes. For example:
>>> foo = 3.1415-2.45j
>>> foo.real
3.1415
>>> foo.imag
-2.45
Finally, Python supports computing the conjugate or a complex number using the conjugate()
method. For example:
>>> foo = 3.1415-2.45j
>>> foo.conjugate()
(3.1415+2.45j)
Numerical Operations¶
Python supports the typical range of numeric operators that you see in other programming languages.
Op | Description |
---|---|
x + y | Sum of x and y |
x - y | Difference of x and y |
x * y | Product of x and y |
x / y | Quotient of x and y |
x // y | Quotient of x and y, floored |
x % y | Remainder of x / y |
x ** y | x raised to the power y |
-x | Negation of x |
Note
One difference between Python 3.x and other languages (including Python 2.x) is that the /
operator does not clip the result and return an integer like it does in other languages. Rather, it returns a float. To obtain the clipped/floored result common to other languages, use the //
operator instead. For example:
>>> 151 / 2
75.5
>>> 151 // 2
75
The built-in’s module contains functions to support some common math operations, namely, abs()
(absolute value) and pow()
(power).
Refer to the math
module (for ordinary numbers) and the cmath
module (for complex numbers) for additional math functions (e.g. power, log, trig, angular, hyperbolic functions and related constants.)
Similar to numeric operators, Python also supports the typical range of bitwise operators:.
Op | Description |
---|---|
x << y | Bitwise shift left x by y bits |
x >> y | Bitwise shift right x by y bits |
x & y | Bitwise AND x with y |
x | y | Bitwise OR x with y |
x ^ y | Bitwise XOR x with y |
~x | Bitwise invert x (1-s compliment) |
The bitwise math operators are only valid for integer types.
All math operators (numeric and bitwise) support augmented assignment (x += y
, x >>= y
etc).
Tip
In Python, augmented assignment is faster then the non-augmented version as Python only reads the variables once.
Finally, it should be no surprise that Python supports the typical range of comparison operators:
Op | Description |
---|---|
x < y | Less-than comparator. |
x > y | Greater-than comparator. |
x <= y | Less-than-or-equal comparator. |
x >= y | Greater-than-or-equal comparator. |
x == y | Equal comparator. |
x != y | Not-equal comparator. |
When performing math operations with mixed numeric types, Python expands the narrow type to the wider type to make them compatible for the operation.
For example: an integer being widened to a float:
>>> 5 + 11.3
16.3
Or, an integer being widened to complex:
>>> 5 + 15-7.3j
(20-7.3j)
You can probably deduce the progression from narrowest to widest as the following:
integerfloatcomplex
Try it!
Try the following:
- Create an integer from the base-4 value of 12.
- Convert the value 47.3 to an integer.
- Create 52 as a floating point number
- Convert 255 to a boolean.
- Create a complex number to represent 3+4i and compute its conjugate.
- Add 2 and 3. What type is the sum?
- Add 12 and 5.5. What type is the sum?
- Add 4 and True. What type is the sum?
- Get the value of 15.875 as an integer ratio.
- Use the modulus operator to determine if 35 is an even number.
- Find the hypotenuse of a right angle triangle with sides 3 and 4.
- Multiple the value of 0b00110 by 4 using bitwise operators.
- Compare 0b1100 to the value of 24 to confirm equality.