0%

70- Advanced Numbers

Go beyond integers and floats. Work with fractions, decimals, complex numbers, and specialized numeric types. Precision and control for advanced computations.

You have worked with integers and floats. They handle most everyday calculations. But sometimes you need more. Exact fractions. Arbitrary precision decimals. Complex numbers (real + imaginary parts). Binary and hexadecimal representations. Bit-level manipulation.
Python provides these advanced numeric types in the standard library. The fractions module gives you rational numbers. The decimal module (already covered) gives you exact decimal arithmetic. The complex type is built-in. And integers themselves support advanced bitwise operations.
This lesson explores these advanced numeric capabilities. You will learn to work with fractions for exact rational arithmetic, use complex numbers for scientific computing, perform bitwise operations, and handle large integers efficiently. These skills are essential for scientific programming, cryptography, and low-level systems work.

🕯️ Magic Note

Python integers have unlimited precision. They can grow to the size of your available memory. This makes Python ideal for cryptographic applications, large prime number generation, and any domain requiring big numbers. Contrast this with C, where integers overflow at 2³¹-1 or 2⁶³-1.

Working with Fractions
The fractions.Fraction class represents rational numbers exactly.

Python

from fractions import Fraction

# Creating fractions

f1 = Fraction(1, 3) # 1/3

f2 = Fraction(2, 5) # 2/5

f3 = Fraction(0.75) # 3/4 (from float)

f4 = Fraction(“3/4”) # 3/4 (from string)

print(f1) # 1/3

print(f1 + f2) # 11/15 (1/3 + 2/5 = 5/15 + 6/15)

print(f1 – f2) # -1/15

print(f1 * f2) # 2/15

print(f1 / f2) # 5/6 (1/3 ÷ 2/5 = 5/6)

# Automatic reduction to lowest terms

f = Fraction(4, 8) # Automatically reduced to 1/2

print(f) # 1/2

# Comparison operators work as expected

print(Fraction(1, 3) < Fraction(1, 2)) # True

# Access numerator and denominator

f = Fraction(3, 4)

print(f.numerator) # 3

print(f.denominator) # 4

# Convert to float (may lose precision)

print(float(Fraction(1, 3))) # 0.3333333333333333

🕯️ Magic Note

Fractions are exact. They never have floating point rounding errors. However, they are slower than floats and can cause denominator blowup (very large integers). Use them when exact rational arithmetic is critical, such as in financial calculations or mathematical proofs.

Fractions Practical Examples
Use fractions for precise measurements and ratios.

Python

from fractions import Fraction

# Recipe scaling (exact proportions)

original = {“flour”: Fraction(2, 3), “sugar”: Fraction(1, 4), “butter”: Fraction(1, 2)}

scale_factor = Fraction(3, 1) # Triple the recipe

scaled = {ing: qty * scale_factor for ing, qty in original.items()}

print(scaled) # {‘flour’: Fraction(2, 1), ‘sugar’: Fraction(3, 4), ‘butter’: Fraction(3, 2)}

# Currency conversion with exact rates

usd_to_eur = Fraction(92, 100) # 0.92 exchange rate

amount = Fraction(10, 1)

converted = amount * usd_to_eur

print(f”$10 = €{float(converted):.2f}”)

# Music intervals (frequency ratios)

perfect_fifth = Fraction(3, 2)

perfect_fourth = Fraction(4, 3)

octave = Fraction(2, 1)

print(f”Perfect fifth ratio: {perfect_fifth}”)

print(f”Fifth + Fourth = {perfect_fifth * perfect_fourth} (octave)”)

Complex Numbers
Python has built-in support for complex numbers (real + imaginary parts).

Python

# Creating complex numbers

z1 = 3 + 4j # Real: 3, Imaginary: 4

z2 = complex(3, 4) # Same as above

z3 = 5j # Pure imaginary: 0 + 5j

# Access real and imaginary parts

print(z1.real) # 3.0

print(z1.imag) # 4.0

print(z1.conjugate()) # 3 – 4j

# Arithmetic with complex numbers

a = 2 + 3j

b = 1 – 1j

print(a + b) # (3+2j)

print(a – b) # (1+4j)

print(a * b) # (5+1j) (2*1 + 2*-1 + 3j*1 + 3j*-1 = 2 -2j +3j -3j² = 5 +1j)

print(a / b) # (-0.5+2.5j)

# Magnitude (absolute value)

print(abs(3 + 4j)) # 5.0 (sqrt(3² + 4²))

🕯️ Magic Note

Complex numbers are essential in electrical engineering, quantum mechanics, signal processing, and control systems. Python’s built-in complex type supports all standard mathematical operations, making it a powerful tool for scientific computing.

Complex Numbers with cmath Module
The cmath module provides mathematical functions for complex numbers.

Python

import cmath, math

z = 1 + 1j

# Phase (angle) in radians

print(cmath.phase(z)) # 0.7853981633974483 (π/4)

# Polar to rectangular conversion

magnitude = 5

angle = cmath.pi / 2 # 90 degrees

z_polar = cmath.rect(magnitude, angle)

print(z_polar) # 5e-17+5j (approximately 0+5j)

# Exponential and logarithmic functions

print(cmath.exp(z)) # e^(1+1j)

print(cmath.log(z)) # Natural log

print(cmath.log10(z)) # Base-10 log

# Trigonometric functions for complex numbers

print(cmath.sin(z))

print(cmath.cos(z))

print(cmath.tan(z))

# Square root (returns both roots, unlike math.sqrt)

print(cmath.sqrt(-1)) # 1j (not raise error)

print(math.sqrt(-1)) # ValueError: math domain error

Arbitrary Precision Integers
Python integers have unlimited precision. They grow as needed.

Python

# Very large integers (no overflow)

big_num = 10 ** 30 # 1 followed by 30 zeros

print(big_num) # 1000000000000000000000000000000

factorial_100 = 1

for i in range(1, 101):

factorial_100 *= i

print(f”100! has {len(str(factorial_100))} digits”) # 158 digits

# Large Fibonacci number

def fib(n):

a, b = 0, 1

for _ in range(n):

a, b = b, a + b

return a

fib_1000 = fib(1000)

print(f”Fibonacci(1000) has {len(str(fib_1000))} digits”) # 209 digits

🕯️ Magic Note

Python integers use a variable-length representation. Small integers (typically -5 to 256) are cached for performance. Larger integers use as many “digits” (in base 2³⁰ or 2¹⁵) as needed. This makes Python ideal for cryptography, primality testing, and exact combinatorial calculations.

Bitwise Operations on Integers
Work directly with the binary representation of integers.

Python

# Binary representation

x = 0b1010 # Binary: 10 in decimal

print(bin(x)) # 0b1010

print(bin(42)) # 0b101010

# Bitwise AND (&)

a = 0b1100 # 12

b = 0b1010 # 10

print(bin(a & b)) # 0b1000 (8)

# Bitwise OR (|)

print(bin(a | b)) # 0b1110 (14)

# Bitwise XOR (^) (exclusive OR)

print(bin(a ^ b)) # 0b0110 (6)

# Bitwise NOT (~)

print(bin(~a)) # -0b1101 (-13) (two’s complement representation)

# Left shift (<<)

print(bin(a << 1)) # 0b11000 (24)

print(bin(a << 2)) # 0b110000 (48)

# Right shift (>>)

print(bin(a >> 1)) # 0b110 (6)

print(bin(a >> 2)) # 0b11 (3)

💡 Bitwise operations are useful for working with flags, permissions, network masks, and low-level hardware control. They are extremely fast (operate at the CPU level).
Practical Example: Flag Management with Bitwise
Use bit flags to combine multiple boolean options in a single integer.

Python

# Define flags as powers of 2

READ = 0b0001 # 1

WRITE = 0b0010 # 2

EXECUTE = 0b0100 # 4

DELETE = 0b1000 # 8

# Combine permissions

permissions = READ | WRITE # 0b0011 (3)

print(f”Binary: {bin(permissions)}”)

# Check if a permission is set

def has_permission(perms, flag):

return (perms & flag) == flag

print(f”Has READ? {has_permission(permissions, READ)}”) # True

print(f”Has EXECUTE? {has_permission(permissions, EXECUTE)}”) # False

# Add a permission

permissions |= EXECUTE # Now has READ | WRITE | EXECUTE

print(f”Has EXECUTE now? {has_permission(permissions, EXECUTE)}”) # True

# Remove a permission

permissions &= ~WRITE

print(f”Has WRITE after removal? {has_permission(permissions, WRITE)}”) # False

# Toggle a permission

permissions ^= READ # If READ set, remove it; if not, add it

🕯️ Magic Note

Bit flags are extremely space-efficient. A single 64-bit integer can represent 64 boolean flags. This pattern is used in system calls, file permissions, window managers, and game engines.

Working with Binary and Hexadecimal Literals
Write numbers in binary, octal, or hexadecimal format.

Python

# Binary (prefix 0b or 0B)

a = 0b1010 # 10

b = 0B1111 # 15

c = 0b1111_0000 # 240 (underscores for readability)

# Octal (prefix 0o or 0O)

d = 0o12 # 10

e = 0O17 # 15

# Hexadecimal (prefix 0x or 0X)

f = 0xA # 10

g = 0XFF # 255

h = 0xDEADBEEF # 3735928559

# Conversions

print(bin(42)) # 0b101010

print(oct(42)) # 0o52

print(hex(42)) # 0x2a

# Convert from binary/octal/hex string to integer

print(int(“1010”, 2)) # 10

print(int(“12”, 8)) # 10

print(int(“A”, 16)) # 10

The numbers Module and Numeric ABCs
The numbers module provides abstract base classes for numeric types.

Python

from numbers import Number, Complex, Real, Rational, Integral

# Check numeric types

print(isinstance(42, Integral)) # True

print(isinstance(3.14, Real)) # True

print(isinstance(3+4j, Complex)) # True

print(isinstance(Fraction(1,2), Rational)) # True

print(isinstance(42, Number)) # True

# Type hierarchy: Number -> Complex -> Real -> Rational -> Integral

def describe_number(x):

if isinstance(x, Integral):

return “Integer”

elif isinstance(x, Rational):

return “Fraction”

elif isinstance(x, Real):

return “Float”

elif isinstance(x, Complex):

return “Complex”

else:

return “Unknown”

print(describe_number(42)) # Integer

print(describe_number(Fraction(1,3))) # Fraction

print(describe_number(3.14)) # Float

print(describe_number(3+4j)) # Complex

Performance Considerations
Different numeric types have different performance characteristics.
TypePerformanceUse Case
intFastestGeneral counting, indexing, loops
floatFastScientific computing, graphics
FractionSlow (exact rational arithmetic)Exact fractions, avoiding floating errors
DecimalModerate (software implementation)Financial calculations, exact decimals
complexFast (hardware accelerated)Electrical engineering, quantum computing

Python

# Performance comparison (conceptual)

# int and float: operations are C-level (very fast)

# Fraction: operations are Python-level (slower, but exact)

# Use the right type for the right job

Common Mistakes with Advanced Numbers
  • Creating Fraction from float loses exactness (Fraction(0.1) not equal to Fraction(1,10))
  • Using complex numbers for purely real calculations (unnecessary overhead)
  • Forgetting that integers are immutable (assigning to bits creates new integers)
  • Not handling division by zero with Fractions (raises ZeroDivisionError)
  • Assuming bitwise operations work on floats (they do not)
Check Your Understanding
  • Write a function that adds two fractions using the Fraction class.
  • What is the result of 3 + 4j multiplied by its conjugate?
  • How do you check if a number is an integer using the numbers module?
  • Write a function that uses bitwise operations to check if a number is even.
  • Convert the decimal number 42 to binary, octal, and hexadecimal strings.
  • Why are fractions slower than floats?

⚡ Whisper

Numbers are not all the same. Integers are exact and fast, growing without bound. Floats are efficient but approximate. Fractions are exact but slower. Decimals are precise for money. Complex numbers open the door to another dimension. Bitwise operations speak the language of computers at the lowest level. Each type has its purpose. Use integers for counting and indexing. Use floats for scientific calculations. Use fractions when exact rational arithmetic matters. Use decimals for money. Use complex numbers for AC circuits and quantum states. Use bitwise for flags and low-level control. The right number type makes your code correct, fast, and clear. Choose wisely. The numbers will obey.

Related posts