In this tutorial, you’ll learn 7 different very important concepts of Python:

- Python
**Numbers**, their**types**,**operations,**and many more - All the
**Arithmetic Operations**supported in Python - All the
**Augmented Assignment Operations**supported in Python - How Python handles the resultant object when you apply arithmetic operations on
**two different types of numbers at once** - Type Casting and Type Conversion
**Number formatting**with string**Built-in**mathematical functions or methods

This tutorial is a complete guide to Python numbers. Topics are discussed in detail and some are **very rare** to find online as of today (because Python 3.8 introduced many new scopes).

It is recommended that you get the basic idea of Python numbers from the previous tutorial 15 Data Types in Python – All in One. Although I’ll try to cover everything from scratch.

This tutorial is going to be a **huge one**. So grab a cup of coffee, turn on soft music in headphones, keep patience, and get started!

## Python Numbers – A Numerical Data Type

Python numbers consist of 3 different data types. They are:

**int**– Integers**float**– Floating point numbers**complex**– Complex numbers

All of these are immutable data types. That means, once they are created, they cannot be changed or modified. If you try to modify them, a new instance will be created.

**int**, **float**, and **complex** are 3 classes in Python. An instance of them is created when you assign one of these types of data to a variable.

### Integers in Python

Integers or **ints** are whole numbers. They can be positive, negative, or zero. But cannot contain a fraction value, scientific notation, or imaginary number. Integer numbers in Python can be of any length, you don’t need to declare any **long** type variable. An integer number **cannot** start with zero (0).

Here are a few examples of Python integers. Use the **type( )** function to check their data type, and the **id( )** function to check their allocated memory location.

This code of block written in a Bash consists of 3 different examples.

- The first part shows 3 instances of Python integers. Their data type has been displayed using the
**type()**function. - The second part shows that a
**decimal integer**cannot start with a zero. To understand the error message properly, read the next section. - The last part shows that
**integers**are immutable. That’s why when changing the value of the variable**num3**, the memory location has been changed, hence a new instance has been created instead of overriding the old one.

Python **int** includes all of the number systems. The **decimal** number system (base 10) is what we’re used to. But **Binary**, **Octal**, **Hexadecimal** are also supported. You can represent these number systems by placing appropriate prefixes before a number. The prefixes are:

Number System | Prefixes |
---|---|

Binary (Base 2) | 0b or 0B |

Octal (Base 8) | 0o or 0O |

Hexadecimal (Base 16) | 0x or 0X |

Notice that** each prefix starts with a zero** followed by a lowercase or uppercase character that represents the number system. That’s why you can’t add a zero before decimal integer.

Binary, Octal, Decimal, Hexadecimal, all of the integers work the same way and support the same set of functionalities. But when you try to print any of them, by default the value is printed in decimal integer.

Now, a few questions may rise in your mind.

### How to convert any integer number to binary in Python?

The most general way to convert an integer number, i.e. binary, octal, decimal, or hexadecimal to binary, is to use the built-in function **bin( )**. Pass it a number in any base, and it will return the binary form of the number. Remember that the returned number is a binary **string**. So to apply any mathematical operation on it, you may convert it into a decimal integer. Read below to know how to do it.

### How to convert any integer number to octal in Python?

Use the built-in function **oct( )**, it’s the most general way.

It can convert any base number.

But again, the returned value is an octal **string**.

### How to convert any integer number to hexadecimal in Python?

Use the built-in **hex()** function.

The returned value is a hexadecimal **string**.

Remember that in hexadecimal, A=10, B=11, C=12, D=13, E=14, F=15.

The letters are not case sensitive. But Python returns in lowercase.

### How to convert binary, octal, or hexadecimal to decimal in Python?

Use the built-in function **int()**. The function takes 2 arguments, the first one is any number, but **must be in a string format**! The second one is the base of that number, but **must be in decimal integer format**! 2 for binary, 8 for octal, 10 for decimal, 16 for hexadecimal. The returned number is a **decimal integer**, not in string format like other functions. One extra feature of the **int()** function is that it’s not limited to only binary, octal, decimal, or hexadecimal. You can use any custom number system, just pass the base of it in the second argument. See the examples to understand it properly. If you’re familiar with number system theory, try justifying the outputs yourself!

### How to convert a float to binary, octal, or hexadecimal in Python?

There is no built-in function in Python to do it at a glance. But some third party modules can do it. However, there are 2 different methods of converting **decimal to binary**. One is the **subtraction method**, and the other one is the **successive division method**. Unfortunately, the successive division method does not work for **float to binary conversion**. And the subtraction method has some limitations. To get the proper answer to this question, follow the **Floating Point Arithmetic: Issues and Limitations** section.

### Float in Python

A **float** or **floating-point** number is the same as an integer, but it includes a decimal point. A float can be positive, negative, or zero. The number 5 is an integer, where 5.0 is a float, although both of them are equal. **Python floats also include scientific notations, infinity, and Nan**.

Python floats has been discussed in detail earlier here in Data Types in Python.

When working with Python numbers, you’ll use floats a lot. Here’s a few examples, notice carefully.

Floats are accurate up to 15 decimal points. Above that, either the decimal part gets truncated or the precision drops.

Two things to notice here:

- A semicolon in Python helps to write multiple commands in one line. Python considers them to be written in different lines.
- The
**len( )**function returns the length of an iterable, e.g. a**string**. So 19 in the last example starts counting from**0**up to**4**including the decimal point.

However, the precision can be increased and controlled using different modules like the **decimal** and the **numpy** modules.

In Scientific notation, a very big or very small number is represented as a power of 10. In Python, the letter **e** or **E** is used to represent it. Here’s some examples.

### NaN and infinity in Python

**NaN**– Stands for**Not a Number**. The term**Undefined**in mathematics is represented by this term.**NaN**is a numeric term, but it’s not a number. One example of NaN is float**inf – inf**. Although**0/0**is also undefined in mathematics, Python returns**ZeroDivisionError**instead of**NaN**.**inf**or**infinity**– Stands for infinity in mathematics.

The use of these two can be a little bit confusing in Python. Note that both of them are **case insensitive** and can be represented in many different ways. To manually use **Nan** or **inf**, use the **float( )** function and pass the value in string format.

There are 4 different ways of declaring **infinity** in Python:

- Using the
**float()**function and passing it a string format of**inf, infinity**(case insensitive) - Using Python’s
**math**module - Using Python’s
**decimal**module - using Python’s third-party
**numpy**module

A module is an already written piece of code that either comes with your Python installation or you need to manually download it. To use the pre-made code of a module, import the module with the **import** command. Here’s a quick overview of modules.

Here’s a list of possible ways of declaring **infinity** in Python.

Notice that the **numpy** module or library is a third-party module. So you must download it manually. If you’ve installed Anaconda, then you already have it. Otherwise, for now, use the online compiler to execute the commands.

Here’s a list of possible ways of declaring **NaN** in Python:

There’re a few operations that can lead you to generate **NaN** values. Here’s a list.

### Floating Point Arithmetic: Issues and Limitations

What is the exact value of 1/3? Is it 0.3? Or 0.33? Or 0.33333333? The more 3’s you add, the more precise it gets. But it cannot be the exact answer. 1/3 + 1/3 + 1/3 = 1. But is 0.33 + 0.33 + 0.33 = 1? No! It’s 0.99! This is a limitation for floating point arithmetic. The same happens in binary floating points.

Computers or hardware store numbers as binary. If you’re familiar with conversion between number systems, remember that a number is represented as the **sum of powers of the base**. For example, to convert 42 decimal to binary:

42 = 0x2^{7} + 0x2^{6} + 1×2^{5} + 0x2^{4} + 1×2^{3} + 0x2^{2} + 1×2^{1} + 0x2^{0} = 00101010

And to convert a floating decimal to binary, the power of 2 will continue to decrease from left to right. For example, to convert 0.6875 from decimal float to binary float:

0.6875 = 1×2^{-1} + 0x2^{-2} + 1×2^{-3} + 1×2^{-4} = 0.1011

This is the best way of converting decimal to binary. But still, there are some numbers that you can’t convert accurately, just like the 1/3 example above. One such number is 1/10. Try this online converter to check its binary representation.

No matter how many 2^{-n} you use, the number 1/10 cannot be represented accurately in binary. If you keep trying, this is what you’ll get:

`0.0001100110011001100110011001100110011001100110011...`

And if Python had to convert the true decimal value of what it stores as binary for 1/10, this is what you would get:

```
>>> 0.1
0.1000000000000000055511151231257827021181583404541015625
```

That’s why Python limits the number of digits it shows you and you get 0.1 as answer. But the problem occurs when you try to apply some arithmetic operations on them. For example, the line 0.1 + 0.2 == 0.3 should return True (‘==’ sign is used to check whether both sides are equal). But Python returns False!

```
>>> 0.1 + 0.2 == 0.3
False
>>> 0.1 + 0.2
0.30000000000000004
```

2 things to keep in mind for floating point arithmetic:

- This limitation is not a bug for Python. This is the nature of Computers.
- Most of the floating point numbers have this limitation.

If you’re still curious, read this official documentation by Python.

### Complex Numbers in Python

Complex numbers are written in the form **x + y**j, where **x** is the real part and **y** is the imaginary part. j is used to indicate the imaginary part. **x** and **y** both can be zero, but you must write the **y**j part as **0**j. Both the real or imaginary parts can be either integers or floats. The presence of j indicates that a number is a complex number.

Python complex number supports 2 methods. One is **.real** which shows the real part of the complex number, other is **.imag** which shows the imaginary part.

Here are a few examples.

```
a = 3+5j
b = -2+10j
c = 3.14j
d = 2.97+0j
e = 1.68e-27 + 2.5j # Space is allowed
f = 69 - 3.2e-10j
g = -10j
print(type(a), type(c), type(e), sep='\t')
print(b, d, g, sep='\t') # Separate the values by a tab
print(f.real) # Shows the real part of f
print(f.imag) # Shows the imaginary part of f
```

**Output**:

```
<class 'complex'> <class 'complex'> <class 'complex'>
(-2+10j) (2.97+0j) (-0-10j)
69.0
-3.2e-10
```

Notice that Python treats both the real and imaginary part of a complex number as floats, even if you declare them as ints! Here’s the proof:

```
num = 6+7j
print(type(num.real))
print(type(num.imag))
```

Output:

```
<class 'float'>
<class 'float'>
```

###### Join Facebook Group

**Public Group**

A group optimized for learning purposes. Track your progress by joining a unit

###### Follow on Quora

**Public Space**

Best place to ask questions! Join the built-in community to get help from others

## Arithmetic Operators in Python

Arithmetic operators help you to perform arithmetic calculations, commonly addition, subtraction, division, and multiplication. Python supports a few more arithmetic operations. Here’s a list of all the arithmetic operators in Python. Look below the table for individual explanations.

Sign | Name | Description |
---|---|---|

+ | Addition | Adds numbers |

– | Subtraction | Subtracts numbers |

* | Multiplication | Multiplies numbers |

/ | Float Division | Divides two numbers. The resultant is a float |

// | Integer Division | Divides two numbers. The resultant is an integer |

% | Modulo | Finds the remainder of a division |

** | Exponential | Raises the second number to the power of the first number |

**Addition (x + y)**: Adds two or more numbers. But the important thing to note here is that if at least one number is a float, then the resultant will be a float. And if at least one number is **complex**, then the resultant will be a complex number.

```
>>> 2+3
5
>>> 2+3.0
5.0
>>> 2 + (3-4j)
(5-4j)
```

**Subtraction(x – y)**: Subtracts two or more numbers. If at least one of the numbers is a float, then the resultant will be a float. And if at least one number is **complex**, then the resultant will be a complex number.

```
>>> 2-3
-1
>>> 2.0-3
-1.0
>>> 2 - (3-4j)
(-1+4j)
```

**Multiplication(x * y)**: Multiplies two or more numbers. If at least one of the numbers is a float, then the resultant will be a float. And if at least one number is a complex, then the resultant will be a complex number.

```
>>> 2*3
6
>>> 2*3.0
6.0
>>> 2 * (3-4j)
(6-8j)
>>> (3-4j) * (5+6j)
(39-2j)
```

**Float Division(x / y)**: Divides two or more numbers. It is named as **float division** because it always returns a value in float data type. However, in the presence of a complex number, the resultant will be a complex number.

```
>>> 2/3
0.6666666666666666
>>> 10/2
5.0
>>> 1.8/3
0.6
>>> (3-4j)/2
(1.5-2j)
```

**Integer Division(x // y)**: Divides two or more numbers. It is named as **integer division** because it always returns the integer part of the resultant. Even if the resultant has a fraction value,** **the** integer division** ignores that part. If at least one of the numbers is a float, then the resultant is a float, but the fraction part shows zero only. However, **complex** numbers do not support this operator.

```
>>> 10//3
3
>>> 10.0//3
3.0
>>> 10.0//2
5.0
>>> (3-4j)//2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't take floor of complex number.
```

**Remainder (x % y)**: Returns the remainder in the division of (**x // y**). For example, **10//3=3** and remainder is one. So **10%3=1**

```
>>> 10%3
1
>>> 10.0%3
1.0
>>> 10.5%3
1.5
>>> (3-4j)%2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't mod complex numbers.
```

**Exponential(x ** y)**: Reads as **x to the power y**, or **x ^{y}**. That means, this operator raises y to be the power of x. Here, x and y can be integer, float, or complex. If at least one of the numbers is a float, then the resultant will be a float. And if at least one number is complex, then the resultant will be a complex number.

```
>>> 2**3
8
>>> 2.5**3
15.625
>>> 2**3.5
11.313708498984761
>>> (3-4j)**2
(-7-24j)
>>> 2**(3-4j)
(-7.461496614688569-2.885492725513448j)
```

## Augmented Assignment Operators in Python

**Augmented assignment operators** help to write **shortcut assignment expressions**. A single equal sign (**=**) is used to assign a value to a variable, hence, it’s an assignment operator. The arithmetic operators are used to perform some arithmetic operations. These are two different operations and sometimes may need two different lines of code. But you can combine them both and write in a single line, hence, it’s called the augmented assignment operator. For example, this is what you may usually do:

```
>>> count = 10
>>> count = count + 1 # increase the value by 1
>>> count
11
```

With the help of **augmented assignment operator**, you can shorten the second line.

```
>>> count = 10
>>> count += 1 # equals to count = count + 1
>>> count
11
```

In **augmented assignment operators**, the equal sign should always come after the arithmetic operator. For count+=1, it means, first increase the value of count by 1, and then assign it back to count. If you try the opposite, i.e. count=+1, then it means, first assign **count** to **zero**, then add 1 to it. Here’s an example:

```
>>> count = 10
>>> count =+ 1 # equals to count = 0; count += 1
>>> count
1
```

Here’s a list of all the **augmented assignment operators** in Python. Say, for each example, **x=10**

Sign | Description | Example | Equivalent | Result |
---|---|---|---|---|

+= | First adds, then assigns back | x += 1 | x = x+1 | 11 |

-= | Subtracts first, then assigns back | x -= 1 | x = x-1 | 9 |

*= | Multiplies first, then assigns back | x *= 2 | x = x*2 | 20 |

/= | Divides first, then assigns back | x /=2 | x = x/2 | 10 |

//= | Integer division and assignment | x //= 2 | x = x//2 | 5 |

%= | Finds the remainder and assigns | x %=3 | x = x%3 | 1 |

**= | Exponential and assignment | x **= 3 | x = x**3 | 1000 |

The augmented assignment operation performs a calculation on a variable and assigns the result to the same memory location, knows as

in-placeoperation. Whereas, using assignment and arithmetic operation separately stores the result in a new memory location, even if the variable name stays the same. Although thisin-place operationis valid only for most mutable objects likelists.

```
var1 = [1, 2]
print(id(var1))
var1 = var1 + [3]
print(id(var1), var1)
print()
var2 = [5, 6]
print(id(var2))
var2 += [7]
print(id(var2), var2)
```

**Output**:

```
139915272862912
139915272503232 [1, 2, 3]
139915272502528
139915272502528 [5, 6, 7]
```

When dealing with large data, for example in Data Science or Machine Learning, the in-place operation assigns the result to the same memory location as before. Thus your device doesn’t get out of memory for large data.

The augmented assignment operations are not always in-place. Read more to understand it properly.

## Type Casting and Type Conversion

Sometimes you may need to specify the type of a variable yourself, specially when you need a fixed type of data to complete your task. The process of specifying the type of a variable is called **type casting**.

Sometimes you may need to change the type of some data you’re working on. The process of changing one type of data to another is called **type conversion**.

Both of the topics are discussed separately, but they are actually the same. For each data type in Python, there is a constructor function with the same name of the data type, which helps in **type casting** and **type conversion**. Here are the ones for Python numbers.

**int( )**: It can construct an integer data type from an**integer**,**float**, or a**string**that contains only a number. If it constructs from a float, then the fraction part is ignored. If it constructs from a string, then the string must contain only an integer value, a**float**is not supported. Additionally, a**complex**number is not supported in**int( )**.

```
>>> a = int(10) # int from an int
>>> b = int(10.5) # int from a float
>>> c = int('10') # int from a string
>>> a;b;c
10
10
10
>>> d = int('10.5') # the string must contain only an integer
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10.5'
>>>
>>> d = int('10M') # the string must contain only an integer
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '10M'
>>>
>>> d = int(3-4j) # complex number is not supported
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to int
```

**float( )**: It can construct a**float**data type from an**integer**,**float**, or a**string**. When converting from a string, it can be a string of either an integer value or a float value. However, converting from a**complex**is not allowed.

```
>>> float(10) # from int to float
10.0
>>> float(10.5) # from float to float
10.5
>>> float('10') # from string that contains an integer value
10.0
>>> float('10.5') # from string that contains a float value
10.5
>>>
>>> float('10.5M') # string cannot contain non-numeric value
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: '10.5M'
>>>
>>> float(3-4j) # complex number is not supported
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float
```

**complex( )**: It can construct a**complex**data type from an**integer**,**float**,**string**, or a**complex**value.

```
>>> complex(10)
(10+0j)
>>> complex(10.5)
(10.5+0j)
>>> complex(3-4j)
(3-4j)
>>> complex('3-4j')
(3-4j)
```

## Formatting Numbers with format() function and f-string

When storing numbers or displaying output, sometimes you might need to store or display it in a fixed format. For example, if a number is **12.3456789**, then you might want to store or display it up to 2 decimal points, such as **12.34**, hence, formatting it up to 2 decimal points.

There are a bunch of ways of formatting. Here I’ll discuss 2 different ways. One is the built-in **format( )** function which is the most common. Another one is the **f-string** method, the most modern way of formatting (introduced in Python 3.6).

The concept of formatting in Python is known as **string formatting**. Because, no matter what process you follow to format a data, the output will always be a string. Let’s see a couple of examples. Don’t try to understand yet!

**Using the format() method:**

```
>>> money = 1234.56 * 1.5 * 0.05
>>> money
92.592
>>>
>>> print("Pay $", format(money, "0.2f"), "to confirm your order")
Pay $ 92.59 to confirm your order
>>> print("Pay $"+ format(money, "0.2f"), "to confirm your order")
Pay $92.59 to confirm your order
>>> type(format(92.592, "0.2f"))
<class 'str'>
>>> format(92.592, '0.1f')
'92.6'
```

To discuss the topic, I’ll follow the last example. You can then modify it depending on your use. Just remember, the returned value is always a **string**.

**Using the f-string**:

```
>>> money = 1234.56 * 1.5 * 0.05
>>> money
92.592
>>>
>>> print(f"Pay ${money:.2f} to confirm your order")
Pay $92.59 to confirm your order
>>> f"{92.592: 0.2f}" # Notice the space after the colon
' 92.59'
>>> f"{92.592:0.2f}"
'92.59'
```

How clean and easy it is! Notice that everything inside the curly braces has a special meaning, even if it’s a simple space after the colon.

### format() Function in Python

The format function takes 2 arguments. Its syntax is:

`format(value, format_specifier)`

**value**: The number you want to format**format_specifier**: A**string**that specifies how the number should be formatted

According to the documentation on **format(**** ****)** function, the **format_specifier** can be anything in this list:

```
[[fill]align][sign][#][0][width][,][.precision][type]
where, the options are
fill ::= any character
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= integer
precision ::= integer
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" |
"g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
```

If you don’t understand the list, skip it for now and get back to it after completing this section. Trust me, you’ll understand each and everything listed here!

### f-string in Python

A **formatted string literal** or **f-string** is a string literal that is prefixed with ‘**f**‘ or ‘**F**‘. Its syntax for numbers is as follows:

```
f"{value:format_specifier}"
F"{value:format_specifier}"
```

If you want the **f-string** to use as a replacement field, ignore the second part and use it like **f”{value}”**. More about it in **string**.

### Formatting Floating Point Numbers

The general format specifier for a floating point number:

`width.precision+f`

**width**: Width of the number**after formatting**. It includes the entire number, even the decimal point.**.precision**: Precision of the floating part. That means, how many digits to include after the decimal point (**.**).**f**: Stands for**float**. It tells what type of number to show after formatting (although it’s still a string). This is known as**type code**.

A few things to notice when formatting floats.

- By default, all types of numbers are right-justified. That means, if the specified width is longer than the length of the value, then the output is right-justified with trailing whitespaces to fulfill the specified width.
- If the specified width is shorter than the length of the value, then formatting ignores the
**width**and only follows the**.precision**value.

**Example in format() function**

```
>>> format(123.321, '10.2f') # width 10, 2 digit precision, float data type
' 123.32'
>>> format(123.321, '8.2f')
' 123.32'
>>> format(123.321, '7.2f') # Notice the length of the output
' 123.32'
>>> format(123.321, '6.2f')
'123.32'
>>> format(123.321, '5.2f')
'123.32'
>>> format(123.321, '4.2f')
'123.32'
>>> format(123.321, '.2f') # Notice this one
'123.32'
>>> format(123.321, '-1.2f')
'123.32'
>>>
>>> print('Your account balance is:', format(123.321, '.2f')+'$')
Your account balance is: 123.32$
```

**Example in f-string:**

```
>>> f'{123.321:10.2f}'
' 123.32'
>>> f'{123.321:8.2f}'
' 123.32'
>>> f'{123.321:7.2f}'
' 123.32'
>>> f'{123.321:6.2f}'
'123.32'
>>> f'{123.321:3.2f}'
'123.32'
>>> f'{123.321:.2f}'
'123.32'
>>>
>>> print(f'Your account balance is {123.321:.2f}$')
Your account balance is 123.32$
```

The

widthvalue is only used to neatly line up data in columns. Otherwise, just use.precision+f. Because, if the width is equal or less than the length of the value, then formatting will ignorewidth.

### Formatting Numbers in Scientific Notation

Scientific notation falls under the **float** data type. Just change the type code to **E** or **e**. Everything else works the same.

**Example in format() function:**

```
>>> format(663800000000, '8.2E')
'6.64E+11'
>>> format(663800000000, '9.2E')
' 6.64E+11'
>>> format(663800000000, '.2E') # It returns in 'E'
'6.64E+11'
>>> format(663800000000, '.3e') # It returns in 'e'
'6.638e+11'
>>> format(663800000000, 'e')
'6.638000e+11'
>>> format(0.000123, 'e')
'1.230000e-04'
>>> format(0.000123, '.2e')
'1.23e-04'
```

**Example in f-string:**

```
>>> f'{663800000000:8.2E}'
'6.64E+11'
>>> f'{663800000000:9.2E}'
' 6.64E+11'
>>> f'{663800000000:.2E}'
'6.64E+11'
>>> f'{663800000000:e}'
'6.638000e+11'
>>> f'{0.000123:e}'
'1.230000e-04'
>>> f'{0.000123:.2e}'
'1.23e-04'
```

Formatting in Scientific notation always puts the decimal point after one non-zero digit.

Now when you’re comfortable with formatting floating point numbers, check out this table:

Type Code | Description |
---|---|

e | Exponent notation. Prints the number in scientific notation using lowercase ‘e‘. The default precision is 6 |

E | Exponent notation. Prints the number in scientific notation using Uppercase ‘E‘. The default precision is 6 |

f | Fixed decimal point notation. The default precision is 6 |

F | Same as ‘f‘, but converts nan to NAN and inf to INF |

Here are the examples:

```
>>> f'{123.456:e}'
'1.234560e+02'
>>> f'{123.456:E}'
'1.234560E+02'
>>> f'{123.456:f}'
'123.456000'
>>> f'{123.456:F}'
'123.456000'
>>>
>>> val1 = float('inf')
>>> val2 = float('nan')
>>> f'{val1:f}, {val2:f}'
'inf, nan'
>>> f'{val1:F}, {val2:F}'
'INF, NAN'
```

### Formatting Integers

Integers include **decimal**, **binary**, **octal**, and **hexadecimal**. Their corresponding type codes are:

Type Code | Description |
---|---|

b | Binary format. Outputs the number in base 2, from any base |

o | Octal format. Outputs the number in base 8, from any base |

d | Decimal format. Outputs the number in base 10, from any base |

x | Hexadecimal format. Outputs the number in base 16, from any base. Uses lowercase for a-f |

X | Hexadecimal format. Outputs the number in base 16, from any base. Uses uppercase for A-F |

c | Character. Converts the integer to the corresponding Unicode character |

None or Empty | Not specifying any type code for number is equivalent to ‘d‘ |

Integers do not need any precision. So you can’t format like **.2d**.

**Examples in format():**

```
>>> format(12345, 'd')
'12345'
>>> format(12345, '10d') # Here 10 is the width
' 12345'
>>> format(12345, 'b')
'11000000111001'
>>> format(12345, 'o')
'30071'
>>> format(999999999, 'x')
'3b9ac9ff'
>>> format(999999999, 'X')
'3B9AC9FF'
>>> format(1234, 'c')
'Ӓ'
>>> format(123, 'c')
'{'
>>> format(12345, 'c')
'〹'
>>> format(12345) # No type means decimal by default
'12345'
>>> format(0xab12) # No type means decimal by default
'43794'
```

**Examples in f-string:**

```
>>> f'{12345:d}'
'12345'
>>> f'{12345:10d}' # Here 10 is the width
' 12345'
>>> f'{12345:b}'
'11000000111001'
>>> f'{12345:o}'
'30071'
>>> f'{9999999999:x}'
'2540be3ff'
>>> f'{9999999999:X}'
'2540BE3FF'
>>> f'{1234:c}'
'Ӓ'
>>> f'{321:c}'
'Ł'
>>> f'{420:c}'
'Ƥ'
>>> f'{12345}' # No type means decimal by default
'12345'
>>> f'{0xab12}' # No type means decimal by default
'43794'
```

Let’s see a few more examples in different bases other than 10.

```
>>> f'{0xabc:b}' # Hex to binary
'101010111100'
>>> f'{0b11001011:c}' # Binary to character
'Ë'
>>> f'{0o7264:d}' # Octal to decimal
'3764'
```

### Inserting Commas

Reading large numbers can get easier if separated by commas. To include the comma separator in the **format_specifier**, type a comma before **precision** or after **width**.

**Examples in format():**

```
>>> format(123456789.12345, '20,.3f') # width+comma+precision+type
' 123,456,789.123'
>>> format(123456789.12345, ',.3f') # comma+precision+type
'123,456,789.123'
>>> format(123456789, ',d') # comma+type
'123,456,789'
>>> format(123456789.1234, ',f') # comma+type; default precision of f is 6
'123,456,789.123400'
```

**Examples in f-string**:

```
>>> f'{123456789.12345:20,.2f}' # width+comma+precision+type
' 123,456,789.12'
>>> f'{123456789.12345:,.2f}' # comma+precision+type
'123,456,789.12'
>>> f'{123456789:,d}' # comma+type
'123,456,789'
>>> f'{123456789.1234:,f}' # comma+type; default precision of f is 6
'123,456,789.123400'
```

### Formatting Numbers as Percentage

To format a number in percentage, use the **%** sign as **format_specifier**. Note that this formatting method falls under the floats section. AND when using **%** as a format specifier, you don’t need to use the type code **f**.

The percentage format specifier (**%**) multiplies the number by **100** and shows in **float** data type, followed by a percentage sign. By default, the precision is **6**, but you can specify it too.

**Example in format()**:

```
>>> format(0.542, '%') # Default precision is 6
'54.200000%'
>>> format(100, '%')
'10000.000000%'
>>> format(0.36213, '.2%') # Setting precision to 2
'36.21%'
>>> format(0.36213, '10.2%') # Defining width to 10
' 36.21%'
```

**Example in f-string**:

```
>>> f'{0.542:%}'
'54.200000%'
>>> f'{42:%}'
'4200.000000%'
>>> f'{0.36213:.2%}'
'36.21%'
>>> f'{0.36213:10.2%}'
' 36.21%'
```

### Assigning Signs to Numbers

In case you want to show the sign of the number, here are a few available options.

**+**: Indicates that a sign should be used for both positive and negative numbers**–**: Indicates that a sign should be used only for a negative number (This is the default behavior)**space**: Indicates that a leading space should be used for positive numbers, and a minus sign for negative numbers

**Example in format()**:

```
>>> format(123, '+')
'+123'
>>> format(-123.34, '+')
'-123.34'
>>> format(123, '-')
'123'
>>> format(-123.34, '-')
'-123.34'
>>> format(123, ' ')
' 123'
>>> format(-123.34, ' ')
'-123.34'
```

**Example in f-string**:

```
>>> f'{123:+}'
'+123'
>>> f'{-123.34:+}'
'-123.34'
>>> f'{123:-}'
'123'
>>> f'{-123.34:-}'
'-123.34'
>>> f'{123: }'
' 123'
>>> f'{-123.34: }'
'-123.34'
```

Notice the last 2 examples and understand why you shouldn’t use a space after the colon just to make your formatting look cleaner. Because it has a special meaning, right?

### Setting Alignment and fill

By default, formatting numbers and strings are printed right-justified. This alignment can be changed by the following options. Remember to use the **alignment** option before **sign** and **width** (is exists).

Sign | Description |
---|---|

< | Left alignment within the available space. This is the default for most objects |

> | Right alignment within the available space. This is the default for numbers |

^ | Center alignment within the available space |

= | Forces the padding to be placed after the sign (if any) but before the digits. By default, the sign (if any) and digits print together. |

[fill sign] | Any character that should be used to fill the paddings generated in alignment. This value must come before the alignment sign. |

**Example in format()**:

```
>>> format(123.456, '<10.2f') # Alignment+width+precision+type
'123.46 '
>>> format(12345, '>10') # Alignment+width
' 12345'
>>> format(12345, '^10') # Alignment+width
' 12345 '
>>> format(12345, '+10') # Without equal sign
' +12345'
>>> format(12345, '=+10') # With equal sign
'+ 12345'
>>>
>>> format(12345, '*<10') # Fill padding with *
'12345*****'
>>> format(12345, '0>10') # Fill padding with 0
'0000012345'
>>> format(12345, '$^10') # Fill padding with $
'$$12345$$$'
>>> format(12345, '0=+10') # Fill padding with 0
'+000012345'
```

**Example in f-string**:

```
>>> f'{123.456:<10.2f}' # Alignment+width+precision+type
'123.46 '
>>> f'{12345:>10}' # Alignment+width
' 12345'
>>> f'{12345:^10}' # Alignment+width
' 12345 '
>>> f'{12345:+10}' # Without equal sign
' +12345'
>>> f'{12345:=+10}' # With equal sign
'+ 12345'
>>>
>>> f'{12345:*<10}' # Fill padding with *
'12345*****'
>>> f'{12345:0>10}' # Fill padding with 0
'0000012345'
>>> f'{12345:$^10}' # Fill padding with $
'$$12345$$$'
>>> f'{12345:0=+10}' # Fill padding with 0
'+000012345'
```

### Grouping Numbers by Thousands using Underscores

When writing a large number, it becomes very tough to keep track of zeros. In mathematics, you use commas to separate thousands and hence can easily track the number. But in Python, you can only use commas by formatting the number into a string. To keep track of large numbers without changing its data type, Python 3.6 introduces underscores as the thousand separators. Here’s how it works.

```
>>> 10,000 - 10 # Can't use commas. Python treats it as 10-10; 0-10
(10, -10)
>>> 10_000 - 10 # Underscore helps here
9990
>>> 10_0_00_000 + 99 # You can add underscores anywhere you want
10000099
>>> 0b1011_1100_1011 + 0b101 # Any base is supported
3024
```

From Python 3.6, you can use underscores to format numbers as thousand separators, like commas as you’ve seen earlier. Any type of number and any base is supported.

For thousands separator in formatting:

Commas are placed after each 3 digits and only supported by

intsandfloats.Underscores are placed after 3 digits for

intsandfloats, and after 4 digits forbinary,octal, andhexadecimal.

**Example in format()**:

```
>>> format(10000000, '_')
'10_000_000'
>>> format(0b10110011001, '_')
'1_433'
>>> format(1433 '_b')
'101_1001_1001'
```

**Example in f-string**:

```
>>> format(1433, '_b')
'101_1001_1001'
>>>
>>> f'{10000000:_}'
'10_000_000'
>>> f'{0b10110011001:_}' # Output in decimal (default), and place '_' after each 3 digits
'1_433'
>>> f'{1433:_b}' # Output in binary, and place '_' after each 4 digits
'101_1001_1001'
```

### “#” – Alternate form of Python numbers

The ‘**#**‘ option causes the alternate form to be used for conversion. Notice the examples above. When you want to use binary, octal, or hexadecimal, you use the prefix 0b, 0o, 0x respectively. But the formatted output does not include any prefix. In case you want to add the prefixes when converting decimals to other bases in formatting, use the ‘**#**‘ option.

**Example in format()**:

```
>>> # Example without '#'
>>> format(54321, 'b')
'1101010000110001'
>>> format(54321, 'o')
'152061'
>>> format(54321, 'x')
'd431'
>>>
>>> # Example with '#'
>>> format(54321, '#b')
'0b1101010000110001'
>>> format(54321, '#o')
'0o152061'
>>> format(54321, '#x')
'0xd431'
```

**Example in f-string**:

```
>>> # Example without '#'
>>> f'{54321:b}'
'1101010000110001'
>>> f'{54321:o}'
'152061'
>>> f'{54321:x}'
'd431'
>>>
>>> # Example with '#'
>>> f'{54321:#b}'
'0b1101010000110001'
>>> f'{54321:#o}'
'0o152061'
>>> f'{54321:#x}'
'0xd431'
```

### Wrapping up Formatting Numbers

Remember the **format_specifier** option list? Now you understand it properly, don’t you? Here’s the list again for you.

The most important thing here is the first line. You must follow the sequence!

```
[[fill]align][sign][#][0][width][,][.precision][type]
where, the options are
fill ::= any character
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= integer
precision ::= integer
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" |
"g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"
```

Last but not the least, let’s see a complete example following the sequence shown in the first line of the above list.

**Example in format()**:

```
>>> format(123456.789, 'f')
'123456.789000'
>>> format(123456.789, '.2f')
'123456.79'
>>> format(123456.789, ',.2f')
'123,456.79'
>>> format(123456.789, '_.2f')
'123_456.79'
>>> format(123456.789, '10,.2f')
'123,456.79'
>>> format(123456.789, '20,.2f')
' 123,456.79'
>>> format(123456.789, '020,.2f') # Fills the gap with zeros
'0,000,000,123,456.79'
>>> format(12345, '#20,b') # Comma is only supported in decimal
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Cannot specify ',' with 'b'.
>>> format(12345, '#20_b')
' 0b11_0000_0011_1001'
>>> format(123456.789, '+#20,.2f')
' +123,456.79'
>>> format(123456.789, '^+#20,.2f')
' +123,456.79 '
>>> format(123456.789, '$^+#20,.2f')
'$$$$+123,456.79$$$$$'
```

**Example in f-string**:

```
>>> f'{123456.789:f}'
'123456.789000'
>>> f'{123456.789:.2f}'
'123456.79'
>>> f'{123456.789:,.2f}'
'123,456.79'
>>> f'{123456.789:_.2f}'
'123_456.79'
>>> f'{123456.789:10,.2f}'
'123,456.79'
>>> f'{123456.789:20,.2f}'
' 123,456.79'
>>> f'{123456.789:020,.2f}'
'0,000,000,123,456.79'
>>> f'{12345:#20,b}' # Comma is only supported in decimal
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: Cannot specify ',' with 'b'.
>>> f'{12345:#20_b}'
' 0b11_0000_0011_1001'
>>> f'{123456.789:+#20,.2f}'
' +123,456.79'
>>> f'{123456.789:^+#20,.2f}'
' +123,456.79 '
>>> f'{123456.789:$^+#20,.2f}'
'$$$$+123,456.79$$$$$'
```

###### Join Facebook Group

**Public Group**

A group optimized for learning purposes. Track your progress by joining a unit

###### Follow on Quora

**Public Space**

Best place to ask questions! Join the built-in community to get help from others

## Built-in Mathematical Functions in Python

There are a total of **69 built-in functions** in Python as of version 3.8.5. **A function is a reusable block of code that performs a specific task**. You can create your own functions, but there are some functions that are very common in programming. So to make your life easy, Python developers have already written some most commonly used functions that you can use just by calling it and supplying appropriate arguments.

**To use a function, call it by its name followed by parenthesis**. A function needs some values to work on. These values are called **arguments**. To make your life even easier, Python developers set some common values as arguments, these are called **default arguments**. The ones you need to provide yourself are called **keyword arguments**. Here is an example:

```
print('Hello','World!') # What you write
print('Hello', 'World!', sep=' ', end='\n', file=sys.stdout, flush=False) # What it actually is
```

**print( )** is a function that outputs values in the standard output. You usually give it the values to print, like ‘Hello’, and ‘World!’ in the example. These are keyword arguments. Python **print( )** function needs a few more arguments to operate appropriately. **sep** contains the character to separate multiple objects (Here ‘Hello’ and ‘World!’). As almost every time you’ll use one whitespace, Python sets it by default for you. The same goes for all the other arguments. These are called **default arguments**. More about them in a future tutorial.

Python has a total of **15 built-in mathematical functions**. They are:

Functions | Description |
---|---|

abs(number) | Returns the absolute value of a number. For complex, returns the magnitude |

max(iterable); max(arg1, arg2, … argN) | Returns the largest item in an iterable (string, list, dictionary, etc.)Returns the largest of 2 or more arguments |

min(iterable); min(arg1, arg2, … argN) | Returns the smallest item in an iterable (string, list, dictionary, etc.)Returns the smallest of 2 or more arguments |

pow(base, exp[, mod]) | Returns base to the power exp, base. ^{exp}If mod is present, then returns base^{exp} % mod |

range(start, stop, step) | Returns a sequence of numbers from start up to stop with an interval of step. Default value: start=0, step=1 |

round(number, [ndigits]) | Returns number rounded to ndigits precision after the decimal point. If ndigits is omitted or is `None` , it returns the nearest integer to its input. |

sum(iterable, total=0) | Sums the numbers of an iterable. total is the variable where the numbers get added one by one |

—– | —– |

len(object) | Returns the length (the number of items) of an object. |

bool(value) | Returns a boolean value, either True or False |

bin(number) | Converts an integer to a binary string, prefixed with ‘0b’ |

complex([real[,imag]]) | Returns a complex number |

float([number]) | Returns a floating-point number generated from a number or string |

hex([number]) | Converts an integer to a hexadecimal string, prefixed with ‘0x’ |

int(x, base=10) | Converts a number or string to an integer in base 10 |

oct(number) | Converts an integer to an octal string, prefixed with ‘0o’ |

Let’s discuss the one’s we haven’t discussed yet.

### abs() function – Absolute Value

The Python **abs( )** function takes a number as an input and returns the absolute value of it. The argument or input can be an integer or float. But if it’s a complex number, then **abs( )** returns the magnitude of it. In mathematics, the magnitude of a complex number **a + bj** is the **square root of (a ^{2} + b^{2})**. However, an absolute value means how big or small a number is compared to zero. Hence, absolute values are always positive.

```
>>> abs(5)
5
>>> abs(-5)
5
>>> abs(10.3)
10.3
>>> abs(-10.3)
10.3
>>> abs(2+3j)
3.605551275463989
>>> (2**2+3**2)**.5 # 2**2 means 2 to the power 2
3.605551275463989
>>> abs(2+3j) == (2**2+3**2)**.5
True
```

### max() function – Find The Maximum

The **max( )** function in Python finds the maximum value from an iterable or from 2 or more arguments.

An iterable means any data type that can contain multiple values in one variable and can be indexed. For example, **string**(can contain multiple alphabets), **list**, **dictionary**, **set,** etc. Read the 15 Data Types in Python to get an overall idea of each of them.

When you supply an iterator to the **max( )** function as an argument; or 2 or more values as multiple arguments, it returns the maximum value.

- If the values are numbers, then the biggest number is returned.
- If the value is a string,
**max( )**converts each character into Unicode and returns the biggest one. - If the values are 2 or more different strings,
**max( )**compares the first character of each argument to detects the biggest argument.

Notice the example to understand it properly.

**When iterators are used:**

```
>>> ord('a') # Checking the Unicode first
97
>>> ord('g')
103
>>> max({'a':10, 'b':9, 'c':8}) # In dictionary, keys are compared
'c'
>>> max([1,5,7,3,9,0,6])
9
>>> max('abcdgfe') # Each character is compared
'g'
```

**When multiple arguments are used:**

```
>>> max(1,9,2,0,3,8,5,6)
9
>>> max('abc', 'def', 'agh') # First character of each are compared
'def'
>>> max('abc', 'def', 'dfg') # If firsts are equal, then second characters are compared
'dfg'
```

Note that if there are multiple maximum values, then the first one encountered is returned.

### min() function – Find The Minimum

The **min( )** function in Python finds the minimum value from an iterable or from 2 or more arguments. It works the opposite of the **max( )** function.

**When iterators are used:**

```
>>> min({'a':10, 'b':9, 'c':8}) # In dictionary, keys are compared
'a'
>>> min([1,5,7,3,9,0,6])
0
>>> min('abcdgfe') # Each character is compared
'a'
```

**When multiple arguments are used:**

```
>>> min(1,9,2,0,3,8,5,6)
0
>>> min('abc', 'def', 'agh')
'abc'
>>> min('abc', 'def', 'aabc')
'aabc'
```

### pow() function – Raise to the Power

The **pow(base, exp[, mod])** takes up to 3 arguments. **base** and **exp** are required arguments, which means these are the must. And **mod** is an optional argument. Although it’s commonly used to find the exponential of a base, it can perform different mathematical operations depending on the arguments. Note that all three arguments must be numeric values.

- When
**base**and**exp**are given, the**pow()**function returns**base**. This is the same as^{exp}**base**exp**. Both raises**exp**to the power of**base**. - When all
**base**,**exp**, and**mod**are given, the function returns**base**. This is the same as^{exp}% mod**(base ** exp) % mod**, but computed more efficiently. When all three arguments are used, all of them must be integers. - When
**exp**is negative and**mod**is also given, the function returns**base**but calculated in modular arithmetic process.^{exp}% mod

**Example 1:**

```
>>> pow(2, 3)
8
>>> 2**3
8
>>> pow(2+3j, 4)
(-119-120j)
>>> (2+3j) ** 4
(-119-120j)
>>> pow(3.5, 4, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pow() 3rd argument not allowed unless all arguments are integers
>>> pow(3.5, 4)
150.0625
>>> pow(3.5, 4.2)
192.79056951583615
```

**Example 2: **

```
>>> pow(2,3,4)
0
>>> 2**3 % 4
0
>>> pow(5,7,3)
2
>>> 5**7 % 3
2
>>> pow(4,11,13)
10
>>> pow(4,11,2.5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pow() 3rd argument not allowed unless all arguments are integers
```

**Example 3:** If you’re not familiar with modular multiplicative inverses from the number theory, read this Stack Overflow answers to understand what’s going on under the hood of the following examples.

```
>>> pow(38, -1, mod=97)
23
>>> 23 * 38 % 97 == 1 # This is what it really does
True
>>> pow(3, -1, 8)
3
>>> pow(10, -3, 42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: base is not invertible for the given modulus
```

Why did the last one returned an error? Notice the first and second examples.

When the **pow( )** function computes the modulo of an inverse number, here **38 ^{-1} % 97**, it actually tries to find a value

**d**such that

**d * base % mod = 1**. Where

**d**can be anything

**from 0 to mod-1**, i.e. in the

**range(97)**.

For the third example, you can’t find any whole number **d** that satisfies the condition **d * base % mod = 1**. That’s why this operation becomes invalid.

To check out the value of **d** manually, run this code and find out where it returns **1**.

```
for i in range(97):
s = f"{i} * 38 % 97"
print(s, "==", eval(s))
```

### range() function – Generate a sequence of numbers

The **range( )** function generates a sequence of integer numbers as a **range** object. Later it can be converted into any sequence types like **list**, **tuple**, and set types like **set**, **frozenset**. A **range( )** function can take up to 3 arguments. One is a required argument and the other two are optional.

**range([start,] stop [, step])**:

**start**: Starting number of the range. It is optional, default value is zero.**stop**: Where to stop the range. It is the only required argument.**step**: The step size of going from**start**to**stop**. In other words, the difference between every 2 elements in the sequence. This is optional. Default value is 1 or +1.**step can’t be zero!**

Note that the second argument is **stop**, and not **end**. Why?

The

range()function starts from thestartand goes up tostop, but excluding it. That means, the sequence ends before thestopvalue.

A few things to note here:

- All three arguments must be integers only
- If only one argument value is passed, it goes to
**stop** - If two arguments are passed, the first one goes to
**start**, and the second one to**stop** - If all three arguments are passed, they go to
**start**,**stop**,**step**serially.

```
>>> range(0, 10, 1)
range(0, 10)
>>> type(range(0, 10))
<class 'range'>
>>> range(10) # start=0, stop=10, step=1
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(0, 30, 5))
[0, 5, 10, 15, 20, 25]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(0)) # star=0,stop=0,step=1; this cannot be done
[]
>>> list(range(1, 0)) # star=1,stop=0,step=1; cannot be done
[]
>>> list(range(10,1)) # star=10,stop=1,step=1; cannot be done
[]
>>> list(range(10,1,-1))
[10, 9, 8, 7, 6, 5, 4, 3, 2]
```

Here’s some example only for negative numbers which might get a little bit confusing.

```
>>> list(range(-10)) # star=0,stop=-10,step=1; this cannot be done
[]
>>> list(range(-10, -1))
[-10, -9, -8, -7, -6, -5, -4, -3, -2]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(-10, -10, -1))
[]
>>> list(range(10, -10, -1))
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
```

The advantage of the

range()function or type over a regularlist,tuple, orsetis that arangeobject will always take the same (and small) amount of memory, no matter the size of the range it represents. Because it only stores thestart,stop, andstepvalues instead of storing every single element, and calculates the elements and sub-ranges as needed.

Range objects provide features like **containment test** (whether a value exists in the range), **element index lookup** (finding the index of an element), **slicing** (creating sub-ranges), and **positive/negative indexing** (finding value with both positive and negative indexing). Here are some examples:

```
>>> r = range(0, 20, 2)
>>> r
range(0, 20, 2)
>>> list(r)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> 13 in r # containment test
False
>>> 6 in r
True
>>> r.index(14) # element index lookup
7
>>> r[5] # indexing
10
>>> r[:5] # slicing
range(0, 10, 2)
>>> list(r[:5])
[0, 2, 4, 6, 8]
>>> r[-1] # negative indexing
18
>>> r[-3]
14
```

### round() function – rounding a number

The **round(number [, ndigits])** has two arguments, where **number** is required and **ndigits** is optional. It returns **number** rounded to **ndigits** precision after the decimal point. If **ndigits** is not provided or is **None**, then it returns an integer closest to the input **number**.

```
>>> round(3.6542, 2)
3.65
>>> round(3.14159265, 3)
3.142
>>> round(3.1449, 2)
3.14
>>> round(3.1450, 2)
3.15
>>> round(3.4)
3
>>> round(3.5)
4
```

**round( )** in Python does not work the same as you might have learned in school. You might have learned the simple always round 0.5 up method. But this process is not efficient. There are lots of ways of rounding numbers. Python 3’s way (Called round half to even or “**banker’s rounding**“) is considered the standard rounding method these days. In this method, every **.5** number is rounded to the nearest **even** digit.

For example, **2.5** can be rounded to **2** or **3**. But as **2** is an even, it rounds down to **2**. On the other hand, **1.5** can be rounded to **1** or **2**. But as **2** is an even, it rounds up to **2**. The same happens for **3.25** and **3.35** when rounding with **ndigits = 1**.

```
>>> round(1.5)
2
>>> round(2.5)
2
>>> round(3.5)
4
>>> round(4.5)
4
>>> round(-1.5)
-2
>>> round(-2.5)
-2
>>> round(-.5)
0
>>> round(.5)
0
>>> round(3.25,1)
3.2
>>> round(3.35,1)
3.4
```

You’ll see some **floating-point numbers not following this rule**. Even they behave differently for different values. For example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug. It’s a result of the fact that **most floating-point numbers cannot be represented exactly** in the binary number system when storing in hardware. Read **Floating Point Arithmetic: Issues and Limitations** above if you don’t remember.

```
>>> round(2.675, 2)
2.67
>>> round(3.15,1) # Expected 3.2
3.1
>>> round(3.25,1)
3.2
>>> round(3.35,1)
3.4
>>> round(3.45,1) # Expected 3.4
3.5
>>> round(3.55,1) # Expected 3.6
3.5
```

### sum() function – Sum up the numbers of an iterable

The **sum(iterable, start=0)** function sums up the numbers of an iterable from left to right. Here, **start** is an optional argument. Consider this as **total**. The function sums every number to it. You can define a different **start** value and the **sum( )** function will add the numbers from this **start** value. But this operation is only supported from Python 3.8.

```
>>> sum([1,2,3,4,5])
15
>>> sum([1,2,3,4,5], start=100)
115
>>> sum(range(10))
45
>>> sum(range(10), start=5)
50
>>> sum([1.5, 2.3, 3.1416, 6.675])
13.616599999999998
```

To add floating point values with extended precision, see **math.fsum()**.

### len() function – Finds the length

The **len(object)** function measures the length of an object. The argument can be a sequence (such as **string**, **bytes**, **tuples**, **list**, or **range**), or a collection (such as **dictionary**, **set**, or **frozenset**), but it cannot be a number (such as **int**, **float**, **complex**, or **boolean**).

```
>>> len('Machine Learning Wiki')
21
>>> len(bytes('MLwiki', encoding='utf-8'))
6
>>> len((1,2,3,4,5))
5
>>> len([1,2,3,4,5])
5
>>> len(range(5))
5
>>> len({'a':1, 'b':2, 'c': 0})
3
>>> len({'a', 'b', 'c'})
3
>>> len(frozenset(['a', 'b', 'c']))
3
>>> len(frozenset({'a', 'b', 'c'}))
3
```

### bool() function – True or False

The **bool(x)** function returns either **True** or **False** depending on the value **x**. The **bool( )** function returns **True** for every single value of **x**, except these values:

**x**is left empty**x = None**,**False**,**0**,**0.0**,**0j**,**Decimal(0)**,**Fraction(0, 1)**- Empty sequence and collections:
**‘ ‘**,**( )**,**[ ]**,**{ }**,**set()**,**range(0)**

Note that **True** equals 1 and **False** equals 0 mathematically.

```
>>> bool()
False
>>> bool(1)
True
>>> bool(-1)
True
>>> bool('text')
True
>>> bool(None)
False
>>> bool(False)
False
>>> bool(0)
False
>>> import decimal
>>> bool(decimal.Decimal(0))
False
>>> bool([])
False
>>> bool(range(0))
False
>>> True + True
2
>>> False + False
0
>>> True + False
1
```

### What’s Next?

Now you have a very good understanding of Python numbers. There are a number of modules and libraries that are dedicated to Python numbers to extend its scope. Those will be discussed after covering all the basics of Python. Here is a list of things you you should try next:

**Bookmark**this tutorial so that you can get back to it whenever it’s necessary- Share it with others. This encourages me!
- Go to Stack Overflow, search for ‘Python’, or ‘Python Numbers’, and answer the questions as many as you can. I expect 3 questions.
- Read the next tutorial to know about all the operators supported in Python. That will be a complete guide to operators.
- Read the tutorials on the following modules and libraries when they are released:
**math**,**decimal**,**random**, and**numpy**

And if you didn’t, read earlier tutorials: