Python Numbers: Integers, Floats, and Complex for AI

Explore Python's numeric types: integers, floats, and complex numbers. Essential for data manipulation and algorithms in AI & machine learning.

1.3 Python Numbers

Python offers several built-in numeric types, providing flexibility for various computational tasks.

Built-in Number Types

Python has three fundamental built-in number types:

  • Integers (int): Whole numbers, positive or negative, without a fractional part.
  • Floating-point numbers (float): Numbers with a fractional part, represented using a decimal point.
  • Complex numbers (complex): Numbers with a real and an imaginary part, written as a + bj.

Additionally, Python has a bool data type, which is a subtype of int. Its two values, True and False, correspond to the integers 1 and 0 respectively.


Integers (int)

An integer is any number that does not have a fractional part. For example, 5678, -89, and 0 are integers. Even 20.0 is considered a float because it includes a fractional part, even if that part is zero.

You can create integers in Python through:

  • Literals: Directly writing the number.
  • Expressions: Using arithmetic operations.
  • int() function: Converting other types to integers.

Creating Integers

Literal:

a = 25
print(f"a: {a}, type: {type(a)}")

Expression:

b = 15
c = 35
d = b + c
print(f"b: {b}, type: {type(b)}")
print(f"d: {d}, type: {type(d)}")

Output:

a: 25, type: <class 'int'>
b: 15, type: <class 'int'>
d: 50, type: <class 'int'>

int() Function:

The int() function can convert strings or floating-point numbers to integers. When converting a float, the fractional part is truncated.

# From a float
a = int(45.9)
print(f"int(45.9): {a}, type: {type(a)}")

# From a string representing an integer
b = int("200")
print(f"int('200'): {b}, type: {type(b)}")

# From a string with a specified base (e.g., binary, octal, hex)
# See specific sections below for more on bases

Output:

int(45.9): 45, type: <class 'int'>
int('200'): 200, type: <class 'int'>

Different Number Bases

Python supports integers represented in binary, octal, and hexadecimal formats.

Binary Numbers

Binary numbers start with the prefix 0b.

# Literal binary
a = 0b110
print(f"a = 0b110: {a}, type: {type(a)}")

# Converting a binary string to an integer
b = int("0b110101", 2) # The second argument '2' specifies base-2
print(f"b = int('0b110101', 2): {b}, type: {type(b)}")

Output:

a = 0b110: 6, type: <class 'int'>
b = int('0b110101', 2): 53, type: <class 'int'>

bin() Function: To get the binary representation of an integer as a string, use the bin() function.

num = 53
binary_representation = bin(num)
print(f"Integer: {num}, Binary equivalent: {binary_representation}")

Output:

Integer: 53, Binary equivalent: 0b110101

Octal Numbers

Octal numbers use digits from 0 to 7 and start with the prefix 0o.

# Literal octal
a = 0o123 # This represents 1*8^2 + 2*8^1 + 3*8^0 = 64 + 16 + 3 = 83
print(f"a = 0o123: {a}, type: {type(a)}")

# Converting an octal string to an integer
b = int('25', 8) # The second argument '8' specifies base-8 (2*8^1 + 5*8^0 = 16 + 5 = 21)
print(f"b = int('25', 8): {b}, type: {type(b)}")

# Addition with octal numbers
val1 = 0o65 # 6*8^1 + 5*8^0 = 48 + 5 = 53
val2 = int("0o40", 8) # 4*8^1 + 0*8^0 = 32
sum_val = val1 + val2
print(f"val1 = 0o65: {val1}, type: {type(val1)}")
print(f"val2 = int('0o40', 8): {val2}, type: {type(val2)}")
print(f"Addition: {sum_val}")

Output:

a = 0o123: 83, type: <class 'int'>
b = int('25', 8): 21, type: <class 'int'>
val1 = 0o65: 53, type: <class 'int'>
val2 = int('0o40', 8): 32, type: <class 'int'>
Addition: 85

oct() Function: To get the octal representation of an integer as a string, use the oct() function.

num = 85
octal_representation = oct(num)
print(f"Integer: {num}, Octal equivalent: {octal_representation}")

Output:

Integer: 85, Octal equivalent: 0o125

Hexadecimal Numbers

Hexadecimal numbers use digits 0-9 and letters A-F (or a-f) and start with the prefix 0x.

# Literal hexadecimal
a = 0xB4 # B is 11, 4 is 4. 11*16^1 + 4*16^0 = 176 + 4 = 180
print(f"a = 0xB4: {a}, type: {type(a)}")

# Converting a hex string to an integer
b = int('0X2a', 16) # 2*16^1 + a(10)*16^0 = 32 + 10 = 42
print(f"b = int('0X2a', 16): {b}, type: {type(b)}")

# Another example
num_string = "C2" # C is 12, 2 is 2. 12*16^1 + 2*16^0 = 192 + 2 = 194
number = int(num_string, 16)
print(f"Hexadecimal: {num_string}, Integer: {number}")

Output:

a = 0xB4: 180, type: <class 'int'>
b = int('0X2a', 16): 42, type: <class 'int'>
Hexadecimal: C2, Integer: 194

Invalid Hexadecimal String: Attempting to convert a string with invalid hexadecimal characters will raise a ValueError.

# num_string = "B3G001" # 'G' is not a valid hex digit
# print(int(num_string, 16))

Error Output:

ValueError: invalid literal for int() with base 16: 'B3G001'

hex() Function: To get the hexadecimal representation of an integer as a string, use the hex() function.

num = 194
hex_representation = hex(num)
print(f"Integer: {num}, Hex equivalent: {hex_representation}")

Output:

Integer: 194, Hex equivalent: 0xc2

Mixed Base Representation: You can mix different base representations in expressions, and Python will handle the conversions internally.

decimal_num = 20
binary_num = 0b1010   # 10 in decimal
octal_num = 0o24      # 20 in decimal
hex_num = 0x14        # 20 in decimal

total_sum = decimal_num + binary_num + octal_num + hex_num
print(f"Sum of mixed bases: {total_sum}") # 20 + 10 + 20 + 20 = 70

Output:

Sum of mixed bases: 70

Floating-Point Numbers (float)

Floating-point numbers have a fractional part. Examples include 8.88, 0.123, -7.77, and -0.321.

Scientific Notation

Floats can be represented using scientific notation, where E or e denotes "times 10 to the power of".

# 1.5 * 10^6
a = 1.5E6
print(f"a = 1.5E6: {a}")

# 7.12 * 10^-4
b = 7.12E-4
print(f"b = 7.12E-4: {b}")

# 1.11 * 10^2
c = 1.11E2
print(f"c = 1.11E2: {c}")

Output:

a = 1.5E6: 1500000.0
b = 7.12E-4: 0.000712
c = 1.11E2: 111.0

Creating Floats

You can create floats using expressions or the float() function.

Using Expression:

x = 15.75
y = 3.15
z = x / y # Division in Python 3 always results in a float
print(f"c = x / y: {z}, type: {type(z)}")

Output:

c = x / y: 5.0, type: <class 'float'>

float() Function:

The float() function can convert integers, strings, or other numeric types to floating-point numbers.

# Without arguments, creates 0.0
a = float()
print(f"float(): {a}")

# From an integer
b = float(30)
print(f"float(30): {b}")

# From binary, octal, and hex representations (after conversion to integer)
c = float(0b11)   # float(3)
d = float(0o12)   # float(10)
e = float(0xF)    # float(15)
print(f"From bases: {c}, {d}, {e}", sep=", ")

# From strings
f = float("-321.45")
g = float("2.34E03") # Represents 2.34 * 10^3
print(f"From strings: f={f}, g={g}")

Output:

float(): 0.0
float(30): 30.0
From bases: 3.0, 10.0, 15.0
From strings: f=-321.45, g=2340.0

Special Float Values

Floats can represent infinity and "Not a Number" (NaN).

# Infinity
inf_val = 1.00E400 # A number too large to represent as a standard float
print(f"Large number: {inf_val}, type: {type(inf_val)}")

inf_val_str = float("Infinity")
print(f"float('Infinity'): {inf_val_str}, type: {type(inf_val_str)}")

# NaN (Not a Number)
nan_val = float('nan')
print(f"float('nan'): {nan_val}")

Output:

Large number: inf, type: <class 'float'>
float('Infinity'): inf, type: <class 'float'>
float('nan'): nan

Complex Numbers (complex)

A complex number has both a real part and an imaginary part. In mathematics, it's often written as $a + bj$, where $j$ is the imaginary unit ($\sqrt{-1}$). Python's complex type directly supports this.

Creating Complex Numbers

You can create complex numbers using literals or the complex() constructor.

# Using literal notation: real_part + imaginary_partj
num1 = 6 + 5j
print(f"Literal complex number: {num1}")

# Using the complex() constructor: complex(real_part, imaginary_part)
num2 = complex(2, -7) # Represents 2 - 7j
print(f"Complex() constructor: {num2}")

Output:

Literal complex number: (6+5j)
Complex() constructor: (2-7j)

Accessing Parts of Complex Numbers

Complex numbers in Python have attributes to access their real and imaginary components, and a method to get their conjugate.

z = 10 - 4j

# Accessing the real part
print(f"Real part of {z}: {z.real}")

# Accessing the imaginary part
print(f"Imaginary part of {z}: {z.imag}")

# Getting the complex conjugate (flips the sign of the imaginary part)
print(f"Conjugate of {z}: {z.conjugate()}")

Output:

Real part of (10-4j): 10.0
Imaginary part of (10-4j): -4.0
Conjugate of (10-4j): (10+4j)

Note: Comparison operators like <, >, <=, >= are not supported for complex numbers as they cannot be ordered.

Arithmetic with Complex Numbers

Python allows standard arithmetic operations (addition, subtraction, multiplication, division) directly with complex numbers.

a = 3 + 2j
b = 1 - 4j

print(f"Addition: {a} + {b} = {a + b}")
print(f"Subtraction: {a} - {b} = {a - b}")
print(f"Multiplication: {a} * {b} = {a * b}")
print(f"Division: {a} / {b} = {a / b}")

# The magnitude (or modulus) of a complex number z = a + bj is sqrt(a^2 + b^2)
print(f"Magnitude of (3 + 4j): {abs(3 + 4j)}") # sqrt(3^2 + 4^2) = sqrt(9 + 16) = sqrt(25) = 5.0

Output:

Addition: (3+2j) + (1-4j) = (4-2j)
Subtraction: (3+2j) - (1-4j) = (2+6j)
Multiplication: (3+2j) * (1-4j) = (11-10j)
Division: (3+2j) / (1-4j) = (-0.2+0.8j)
Magnitude of (3 + 4j): 5.0

The math Module

The math module provides access to mathematical functions and constants defined by the C standard library. It's essential for advanced mathematical operations.

import math

Mathematical Constants

The module includes useful mathematical constants:

ConstantDescriptionExample Value
math.piThe ratio of a circle's circumference to its diameter (π)$\approx 3.14159$
math.eEuler's number (base of natural logarithms)$\approx 2.71828$
math.tauTwice the value of math.pi ($\tau = 2\pi$)$\approx 6.28318$
print(f"Value of pi: {math.pi}")
print(f"Value of e: {math.e}")
print(f"Value of tau: {math.tau}")

Power and Logarithmic Functions

FunctionDescription
math.pow(x, y)Returns x raised to the power of y.
math.sqrt(x)Returns the square root of x.
math.exp(x)Returns e raised to the power of x.
math.log(x, base)Returns the logarithm of x to the given base.
math.log10(x)Returns the base-10 logarithm of x.
math.log2(x)Returns the base-2 logarithm of x.
print(f"2 raised to the power of 5: {math.pow(2, 5)}")
print(f"Square root of 49: {math.sqrt(49)}")
print(f"e raised to the power of 1: {math.exp(1)}")
print(f"Logarithm of 100 to base 10: {math.log(100, 10)}")
print(f"Logarithm of 100 to base e: {math.log(100)}") # Equivalent to math.log(100, math.e)

Trigonometric Functions

These functions expect angles in radians.

FunctionDescription
math.sin(x)Sine of angle x (in radians).
math.cos(x)Cosine of angle x (in radians).
math.tan(x)Tangent of angle x (in radians).
math.radians(x)Converts angle x from degrees to radians.
angle_deg = 60
angle_rad = math.radians(angle_deg)

print(f"Sine of {angle_deg} degrees ({angle_rad:.2f} rad): {math.sin(angle_rad)}")
print(f"Cosine of {angle_deg} degrees ({angle_rad:.2f} rad): {math.cos(angle_rad)}")
print(f"Tangent of {angle_deg} degrees ({angle_rad:.2f} rad): {math.tan(angle_rad)}")

Inverse Trigonometric Functions

These functions return angles in radians.

FunctionDescription
math.asin(x)Inverse sine (arcsin).
math.acos(x)Inverse cosine (arccos).
math.atan(x)Inverse tangent (arctan).
math.degrees(x)Converts angle x from radians to degrees.
# Finding the angle whose cosine is 0.5
angle_in_radians = math.acos(0.5)
angle_in_degrees = math.degrees(angle_in_radians)
print(f"Angle (in degrees) whose cosine is 0.5: {angle_in_degrees}")

Hyperbolic Functions

These functions are analogous to trigonometric functions but are based on the hyperbola.

FunctionDescription
math.sinh(x)Hyperbolic sine.
math.cosh(x)Hyperbolic cosine.
math.tanh(x)Hyperbolic tangent.
print(f"Hyperbolic sine of 2: {math.sinh(2)}")

Special Functions

FunctionDescription
math.factorial(n)Factorial of non-negative integer n.
math.gcd(a, b)Greatest Common Divisor of integers a and b.
math.lcm(a, b)Least Common Multiple of integers a and b (Python 3.9+).
math.fabs(x)Absolute value of x as a float.
print(f"Factorial of 5: {math.factorial(5)}")
print(f"GCD of 36 and 60: {math.gcd(36, 60)}")
print(f"Absolute value of -7.5: {math.fabs(-7.5)}")

Rounding and Numeric Utilities

FunctionDescription
math.ceil(x)Rounds x up to the nearest integer.
math.floor(x)Rounds x down to the nearest integer.
math.trunc(x)Truncates x by removing the fractional part.
math.modf(x)Splits x into its fractional and integer parts, returning them as a tuple (fractional, integer). Both parts have the same sign as x.
print(f"Ceiling of 5.4: {math.ceil(5.4)}")      # Rounds up to 6
print(f"Floor of 5.4: {math.floor(5.4)}")      # Rounds down to 5
print(f"Truncate of 5.9: {math.trunc(5.9)}")    # Removes decimal, result is 5
print(f"Split 7.25: {math.modf(7.25)}")        # Returns (0.25, 7.0)
print(f"Split -7.25: {math.modf(-7.25)}")       # Returns (-0.25, -7.0)

The random Module

The random module is used for generating pseudo-random numbers and performing random actions, such as shuffling lists or selecting random elements. It's widely used in simulations, games, and data sampling.

import random

Random Number Generation

FunctionDescription
random.random()Returns a random float in the interval [0.0, 1.0).
random.uniform(a, b)Returns a random float N such that a <= N <= b for a <= b and b <= N <= a for b < a.
random.randint(a, b)Returns a random integer N such that a <= N <= b. Includes both endpoints.
random.randrange(start, stop[, step])Returns a randomly selected element from range(start, stop, step).
print(f"Random float [0.0, 1.0): {random.random()}")
print(f"Random float between 10 and 20: {random.uniform(10, 20)}")
print(f"Random integer between 5 and 10: {random.randint(5, 10)}")
print(f"Random integer from range(0, 100, 10) (multiples of 10): {random.randrange(0, 100, 10)}")

Working with Lists (Sequences)

FunctionDescription
random.choice(seq)Returns a random element from a non-empty sequence seq.
random.shuffle(seq)Shuffles the sequence seq in-place.
random.sample(seq, k)Returns a list of k unique elements chosen from the sequence seq.
fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']

print(f"Random choice from fruits: {random.choice(fruits)}")

# Shuffle the list in-place
print(f"Original fruits: {fruits}")
random.shuffle(fruits)
print(f"Shuffled fruits: {fruits}")

# Select 2 unique items from the shuffled list
print(f"2 unique random samples: {random.sample(fruits, 2)}")

Setting a Seed

To ensure reproducible results for random operations (e.g., for testing or debugging), you can set the random seed. The same seed will always produce the same sequence of "random" numbers.

random.seed(42) # Setting the seed to 42
print(f"Random integer after seed 42: {random.randint(1, 10)}")

random.seed(42) # Resetting the seed to 42
print(f"Another random integer after resetting seed 42: {random.randint(1, 10)}") # Will be the same as the previous line

Output:

Random integer after seed 42: 6
Another random integer after resetting seed 42: 6