# Python Numbers

Python provides three numeric data types to handle various kinds of numbers: `int`

, `float`

, and `complex`

.

## Integers (`int`

)

In Python, integers are whole numbers without any decimal points. They can be positive, negative, or zero.

For example:

```
x = 22 # A positive integer
y = -10 # A negative integer
z = 0 # A zero integer
print(type(x)) # <class 'int'>
print(type(y)) # <class 'int'>
print(type(z)) # <class 'int'>
```

The `type()`

function is used to determine the type of an object. It returns the class type of the given object.

Integers in Python have arbitrary precision, meaning they can grow in size as large as the available memory on your system allows. This means you can work with large numbers without worrying about overflow errors.

For example:

```
# A large integer in Python
large_number = 9999999999999999999999999999999999999999
print(large_number)
# Output: 9999999999999999999999999999999999999999
```

## Floating-point Numbers (`float`

)

In Python, `float`

represents a floating-point number, which is a number that contains a decimal point.

For example:

```
x = 22.5 # A positive float
y = -3.7 # A negative float
z = 0.0 # A zero float
```

### Scientific Notation

Python’s `float`

supports scientific notation, where a number is represented in power of ten.

For example:

```
x = 2e2
print(x) # Output: 200.0
print(type(x)) # Output: <class 'float'>
```

In the above example, `e`

stands for the exponent, and the number after it represents the power of `10`

. So, `2e2`

is equivalent to `2 * 10^2`

, which equals `200.0`

. The scientific notation in Python always results in a `float`

.

### Float Precision

Floats in Python use the IEEE 754 double-precision format and typically have a limited precision of 15-17 digits. This means they cannot represent all decimal numbers exactly. As a result, you may encounter slight rounding errors when performing calculations with floats.

For example:

```
print(0.1 + 0.2) # 0.30000000000000004 (Small precision error)
```

### Avoiding Float Precision Issues with the `decimal`

Module

For precision decimal arithmetic, especially in financial applications, you can use the `decimal`

module to avoid precision issues.

For example:

```
from decimal import Decimal
x = Decimal('0.1') + Decimal('0.2')
print(x) # Output: 0.3 (Exact result)
```

## Complex Numbers (`complex`

)

In Python, `complex`

represents complex numbers of the form `a + bj`

, where `a`

is the real part, `b`

is the imaginary part, and `j`

is the imaginary unit.

For example:

```
complex_num = 3 + 4j
print(type(complex_num)) # <class 'complex'>
```

## Type Conversion in Python

In Python, type conversion is the process of converting one data type into another. Type conversions are important when you need to perform operations between different numeric types, such as integers and floats.

Python provides two ways to handle type conversion: implicit and explicit conversion

### (1) Implicit Type Conversion

Implicit type conversion (coercion) happens automatically when Python converts one data type to another without explicit instruction from the programmer. This usually happens when an operation involves two different numerical types, and Python needs to unify the types for the operation to work smoothly.

Python typically converts integers to floats to maintain precision and prevent data loss. If an operation involves a complex number and any other numeric type (`int`

or `float`

), the result is converted to a complex number to preserve both the real and imaginary parts.

For example:

```
x = 2 # int
y = 3.1 # float
# Adding integer and float (integer is converted to float)
z = x + y
print(z) # Output: 5.1
print(type(z)) # Output: <class 'float'>
a = 5 # int
b = 2 + 3j # complex
# Adding integer and complex number (integer is converted to complex)
c = a + b
print(c) # Output: (7 + 3j)
print(type(c)) # Output: <class 'complex'>
```

### (2) Explicit Type Conversion

You can explicitly convert a number from one type to another using built-in functions like `int()`

, `float()`

, and `complex()`

. This is typically used when you need to ensure that a value is of a specific type, often when reading input from a user or working with mixed data type.

#### Conversion Functions

`int()`

: Converts a number or string to an integer`float()`

: Converts a number or string to float`complex()`

: Converts numbers to complex type

Example of Explicit Type Conversion:

```
x = 2 # integer
y = 3.1 # float
z = 1 + 2j # complex
s = "44" # string
# Converting integer to float
a = float(x)
# Converting float to integer
b = int(y)
# Converting integer and float to complex
c = complex(x)
d = complex(y)
# Converting string to integer or float
e = int(s)
f = float(s)
print(a) # 2.0
print(b) # 3
print(c) # (2+0j)
print(d) # (3.1+0j)
print(e) # 44
print(f) # 44.0
print(type(a)) # <class 'float'>
print(type(b)) # <class 'int'>
print(type(c)) # <class 'complex'>
print(type(d)) # <class 'complex'>
print(type(e)) # <class 'int'>
print(type(f)) # <class 'float'>
```

#### Key Points:

- When converting a float to an integer, the decimal part is truncated.
- When converting strings to numbers, the string must represent a valid number.
- You cannot directly convert complex numbers to
`int`

or`float`

.

## Random Numbers in Python (`random`

Module)

In Python, random numbers can be generated using the `random`

module, which provides various methods for generating random values.

### Methods of `random`

module:

`random()`

: Generates a random`float`

between`0.0`

to`1.0`

.`randint(a, b)`

: Returns a random`integer`

between`a`

and`b`

(inclusive).`uniform(a, b)`

: Returns a random`float`

between`a`

and`b`

.`choice(sequence)`

: Selects a random element from a sequence (list, tuple, etc).`shuffle(list)`

: Randomly shuffles the elements of a list.`randrange(start, stop, step)`

: Returns a random number from a range with an optional step.

Example:

```
import random
# random()
print("Random float between 0 and 1.0:", random.random())
# randint()
print("Random integer between 1 and 10:", random.randint(1, 10))
# uniform()
print("Random float between 1.5 and 9.5:", random.uniform(1.5, 9.5))
# choice()
my_list = [5, 10, 15, 20, 25]
print("Random choice from list:", random.choice(my_list))
# shuffle()
random.shuffle(my_list)
print("List after shuffling:", my_list)
# randrange()
print("Random number between 0 and 10 (step 2):", random.randrange(0, 10, 2))
```

## Mathematical Operations on Numbers

Python supports a variety of mathematical operations on integers, floats, and complex numbers.

### 1. Addition and Subtraction (`+`

, `-`

)

Integers and Floats: When adding or subtracting, if either operand is a float, the result will be a float to maintain precision.

For example:

```
x = 5 # int
y = 3.1 # float
result_add = x + y
result_sub = x - y
print(result_add) # Output: 8.1 (float)
print(result_sub) # Output: 1.9 (float)
```

Complex Numbers: When complex numbers are involved, Python adds or subtracts both the real and imaginary parts, and the result is converted to a complex number to preserve both the real and imaginary parts.

For example:

```
a = 2 + 3j # complex
b = 5 # int
result_add = a + b
result_sub = a - b
print(result_add) # Output: (7+3j)
print(result_sub) # Output: (-3+3j)
```

### 2. Multiplication (`*`

)

Integers and Floats: The result is a float if either operand is a float.

For example:

```
x = 5
y = 3.1
result_mult = x * y
print(result_mult) # Output: 15.5 (float)
```

Complex Numbers: Python multiplies complex numbers using the formula: `(a + bj) (c + dj) = (ac - bd) + (ad + bc)j`

For example:

```
a = 1 + 2j
b = 2 + 3j
result_mult = a * b
print(result_mult) # Output: (-4+7j)
```

### 3. Division (`/`

)

Integers and Floats: Division always results in a float, even if both operands are integers.

For example:

```
a = 6
b = 2
result_div = a / b
print(result_div) # Output: 3.0 (float)
```

Complex Numbers: Python divides complex numbers by applying the following formula:

`a + bj / c + dj = (ac + bd) + (bc -ad)j / c2 + d2`

For example:

```
a = 4 + 8j
b = 2 + 2j
result_div = a / b
print(result_div) # Output: (3 + 1j)
```

### Built-in Mathematical Functions

Python provides several built-in functions to perform mathematical operations:

`abs(x)`

: Returns the absolute value of`x`

.`pow(x, y)`

: Raises`x`

to the power of`y`

.`round(x, n)`

: Rounds`x`

to`n`

decimal places (if`n`

is omitted, rounds to the nearest integer).`min(x, y, …)`

: Returns the smallest value among`x`

,`y`

, and other arguments.`max(x, y, …)`

: Returns the largest value among`x`

,`y`

, and other arguments.`sum(iterable, start)`

: Returns the sum of elements in the iterable, starting from`start`

(default is 0).

For example:

```
# abs()
x = -5
print(abs(-5)) # Output: 5
# pow()
x = 2
y = 3
print(pow(x, y)) # Output: 8
# round()
x = 3.14159
print(round(x, 2)) # Output: 3.14
print(round(x)) # Output: 3
# min()
a = 5
b = 10
c = 15
print(min(a, b, c)) # Output: 5
# max()
print(max(a, b, c)) # Output: 15
# sum()
nums = [1, 2, 3]
print(sum(nums)) # Output: 6
print(sum(nums, 10)) # Output: 16 (starts from 10)
```

## Python’s `math`

Module

The Python `math`

module provides a wide range of mathematical functions that are essential for various numerical computations. It offers functions for trigonometry, logarithms, exponentials, and other mathematical operations.

### 1. Basic Mathematical Functions

`math.sqrt(x)`

: Returns square root of`x`

.`math.pow(x, y)`

: Returns`x`

raised to the power of`y`

(similar to the built-in`pow()`

function, but always returns a float).`math.ceil(x)`

: Rounds`x`

up to the nearest integer.`math.floor(x)`

: Rounds`x`

down to the nearest integer.

Example:

```
import math
# math.sqrt(x)
x = 16
print(math.sqrt(x)) # Output: 4.0
# math.pow(x, y)
x = 2
y = 3
print(math.pow(x, y)) # Output: 8.0
# math.ceil(x)
x = 4.1
print(math.ceil(x)) # Output: 5
# math.floor(x)
x = 4.9
print(math.floor(x)) # Output: 4
```

### 2. Exponential and Logarithmic Functions:

`math.exp(x)`

: Returns the value of`e^x`

(Exponential of`x`

).`math.log(x, base)`

: Returns the logarithm of`x`

to the specified base. If no base is provided, it defaults to the natural logarithm (base e).`math.log10(x)`

: Returns the base-10 logarithm of`x`

.`math.log2(x)`

: Returns the base-2 logarithm of`x`

.

Example:

```
import math
# math.exp(x)
x = 2
print(math.exp(x)) # Output: 7.38905609893065 (e^2)
# math.log(x, base)
x = 10
print(math.log(x)) # Output: 2.302585092994046 (natural log of 10)
print(math.log(x, 10)) # Output: 1.0 (log base 10 of 10)
# math.log10(x)
x = 100
print(math.log10(x)) # Output: 2.0 (log base 10 of 100)
# math.log2(x)
x = 8
print(math.log2(x)) # Output: 3.0 (log base 2 of 8)
```

### 3. Trigonometric Functions:

`math.sin(x)`

: Returns the sine of`x`

(in radians).`math.cos(x)`

: Returns the cosine of`x`

(in radians).`math.tan(x)`

: Returns the tangent of`x`

(in radians).`math.degrees(x)`

: Converts angle`x`

from radians to degrees.`math.radians(x)`

: Converts angle`x`

from degrees to radians.

Example:

```
import math
# Define an angle in degrees
angle_degrees = 45
# Convert the angle to radians
angle_radians = math.radians(angle_degrees)
# Compute the trigonometric functions
sin_value = math.sin(angle_radians)
cos_value = math.cos(angle_radians)
tan_value = math.tan(angle_radians)
# Convert the angle back to degrees
print("Sin of 45 degree:", sin_value) # Output: Sin of 45 degree: 0.7071067811865476
print("Cos of 45 degrees:", cos_value) # Output: cos of 45 degree: 0.7071067811865476
print("tan of 45 degree:", tan_value) # Output: tan of 45 degree: 0.9999999999999999
```