Five out of four people have trouble with fractions, Steven Wright.

A **fraction is a fancy way of representing the division of a whole into parts**, for example, half of a pizza (1⁄2), a quarter of an apple (1⁄4), etc.

**The fractions module provides support for rational number arithmetic. We can create fractions from integers, floats, decimals, and strings.**

```
Hi@Welcome:~ python
Python 3.8.6 (default, May 27 2021, 13:28:02)
>>> from fractions import Fraction # Firstly, we need to import the fractions module.
>>> print(Fraction()) # A fraction is formed by a pair of integers as numerator and denominator. The default values for the numerator and denominator are 1 and 0 respectively.
0
>>> print(Fraction(0.25)) # The class Fraction accepts floating point numbers as arguments.
1/4
>>> print(Fraction(8, 20)) # It creates a new fraction and it will be automatically normalized, i.e., it calculates the irreducible fraction.
2/5
>>> print(Fraction(6, 14))
3/7
>>> import math
>>> print (math.gcd(8, 20)) # The Highest Common Factor (gcd) can be obtained in Python using a single function offered by the math module.
4
```

^{8}⁄_{20} = ^{8: gcd(8,20)}⁄_{20: gcd(8, 20)} = ^{8: 4}⁄_{20: 4}= ^{2}⁄_{5}

```
>>> print (math.gcd(6, 14))
2
>>> print(Fraction(2, 0))
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.10/fractions.py", line 156, in __new__
raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
ZeroDivisionError: Fraction(2, 0)
```

**Fraction raises a ZeroDivisionError exception when the argument passed as denominator is 0.**

```
>>> print(Fraction("7/8"))
7/8
>>> print(Fraction(0.75))
3/4
>>> print(Fraction(2.3))
2589569785738035/1125899906842624
```

What’s going on? In base 10 which you’re likely to be comfortable with, you can’t express 1/3 exactly. It’s 0.3333333… (recurring). The same goes with 2.3 in base 2 = 10.0100110011001100110011001100110011001100110011001100110011…2. In other words, **some decimal numbers cannot be represented exactly in binary.**

```
>>> (2.3).as_integer_ratio()
# Returns a pair of integers whose ratio is exactly equal to the original float and with a positive denominator.
```

(2589569785738035, 1125899906842624)

```
>>> Fraction(2, 3) + Fraction(4, 5) # Doing arithmetic with rational numbers is as easy as pie.
Fraction(22, 15)
>>> Fraction(2, 3) + 5
Fraction(17, 3)
>>> Fraction(2, 3) + 5 -0.2
5.466666666666667
>>> Fraction(2, 3) - Fraction(4, 5)
Fraction(-2, 15)
>>> Fraction(2, 3) - 5
Fraction(-13, 3)
>>> Fraction(2, 3) * Fraction(4, 5)
Fraction(8, 15)
>>> Fraction(2, 3) * 7
Fraction(14, 3)
>>> Fraction(2, 3) / Fraction(4, 5)
Fraction(5, 6)
>>> Fraction(2, 3) / 7
Fraction(2, 21)
>>> Fraction(2, 3)**2
```

```
Fraction(4, 9)
>>> Fraction(2, 3) < Fraction(4, 5) # We can see how Python's comparison operators work on fractions.
True
>>> Fraction(2, 3) > 5.2
False
```

```
# It is necessary to overload
from __future__ import division
def gcd(a, b):
""" It returns the greatest common divisor of a and b."""
while b:
a, b = b, a % b
return a
class Fraction:
## A Fraction instance is constructed from a pair of integers.
# @param n is the numerator of the fraction (default is 0)
# @param d is the denominator of the fraction (default is 1)
def __init__(self, n = 0, d = 1):
if (not isinstance(n, int)):
raise TypeError("The numerator of a Fraction must be an integer")
if (not isinstance(d, int)):
raise TypeError("The denominator of a Fraction must be an integer")
self.numerator = int(n / gcd(abs(n), abs(d)))
# It creates a new fraction and it will be automatically normalized, i.e., it calculates the irreducible fraction.
# print(Fraction(8, 20)) returns 2/5.
self.denominator = int(d / gcd(abs(n), abs(d)))
if self.denominator < 0:
self.denominator = abs(self.denominator)
self.numerator = -1*self.numerator
# The denominator cannot be zero, so it raises a ZeroDivisionError if denominator = 0.
elif self.denominator == 0:
raise ZeroDivisionError("Denominator cannot be zero")
@classmethod
def from_string(cls, text):
""" It generates a Fraction object from a string representation of two integers separated by '/'.
>> print(Fraction.from_string('4/9')) return 4/9. Credits: jonrsharpe, codereview.stackexchange.com"""
return cls(*[int(i) for i in text.split('/')])
## It implements the addition of two fractions.
# @params other is the fraction from which self is to be added.
# @return the new Fraction object that is the result of self + other.
def __add__(self, other):
if isinstance(other, int):
other = Fraction(other)
num = self.numerator * other.denominator + self.denominator * other.numerator
den = self.denominator * other.denominator
return Fraction (num, den)
__radd__ = __add__
```

**radd** is called if the left object does not have an **add** method or that method does not know how to add the two objects, e.g., f1 = Fraction(1, 3), print(2 + f1).

```
## It implements the subtraction of two fractions.
# @params other is the fraction from which self is to be subtracted.
# @return the new Fraction object that is the result of self - other.
def __sub__(self, other):
if isinstance(other, int):
other = Fraction(other)
num = self.numerator * other.denominator - self.denominator * other.numerator
den = self.denominator * other.denominator
return Fraction (num, den)
def __rsub__(self, other):
return Fraction(other) - self
## It determines if this fraction is equal to another fraction.
# @params other is the right-hand side fraction.
# @return True if both fractions (self and other) are equal. Otherwise, it returns False.
def __eq__(self, other):
return (self.numerator == other.numerator and self.denominator == other.denominator)
def __lt__(self, other):
# We can implement the __lt__ method by putting self and other in common terms and then comparing the numerators.
return (self.numerator * other.denominator < self.denominator * other.numerator)
def __ne__(self, other):
return not self == other
def __le__(self, other):
return self < other or self == other
def __gt__(self, other):
return other < self
def __ge__(self, other):
return self > other or self == other
## It implements the multiplication of two fractions.
# @params other is the fraction from which self is to be multiplied.
# @return the new Fraction object that is the result of self multiplied by other.
def __mul__(self, other):
if isinstance(other, int):
other = Fraction(other)
return Fraction(self.numerator * other.numerator, self.denominator * other.denominator)
__rmul__ = __mul__
## It implements the division of two fractions.
# @params other is the fraction from which self is to be divided.
# @return the new Fraction object that is the result of self divided by other.
def __truediv__(self, other):
if isinstance(other, int):
other = Fraction(other)
return Fraction(self.numerator * other.denominator, self.denominator * other.numerator)
def __rtruediv__(self, other):
return Fraction(other)/self
def __float__(self):
return self.numerator / self.denominator
## It converts the object into a string.
# @return a string in the format numerator/denominator. If the object represents an improper function (it has a numerator that is greater
# than the denominator), it returns the fraction as a mixed fraction written as the sum of a whole number and a proper fraction.
def __str__(self):
if self.denominator == 1:
return str(self.numerator)
elif abs(self.numerator) > self.denominator:
if self.numerator > 0:
a = self.numerator // self.denominator
b = self.numerator % self.denominator
return "{} {}/{}".format(a, b, self.denominator)
else:
a = - (abs(self.numerator) // self.denominator)
b = - (abs(self.numerator) % self.denominator)
return "{} {}/{}".format(a, -b, self.denominator)
else:
return str(self.numerator) + "/" + str(self.denominator)
def main():
print(Fraction(2, -1)) # -2
print(Fraction(8, 20)) # 2/5
print(Fraction(5, 4)) # 1 1/4
print(Fraction.from_string('4/9')) # 4/9
f0 = Fraction.from_string('3/4')
print(2+f0) # 2 3/4
print(2-f0) # 1 1/4
print(2*f0) # 1 1/2
print(2/f0) # 2 2/3
f1 = Fraction(5, 3)
f2 = Fraction(3, -4)
try:
f3 = Fraction(3, 0)
except ZeroDivisionError:
print("Oops! Denominator cannot be zero")
f3 = f1 + f2
print(f1, "+", f2, "=", f3) # 1 2/3 + -3/4 = 11/12
f3 = f1 - f2
print(f1, "-", f2, "=", f3) # 1 2/3 - -3/4 = 2 5/12
f3 = f1 * f2
print(f1, "*", f2, "=", f3) # 1 2/3 * -3/4 = -1 1/4
f3 = f1 / f2
print(f1, "/", f2, "=", f3) 1 2/3 / -3/4 = -2 2/9
f3 = Fraction(4, 6)
print("Is", f3, " = ", f1, "?=", f3 == f1) # Is 2/3 = 1 2/3 ?= False
print("Is", f3, " < ", f1, "?=", f3 < f1) # Is 2/3 < 1 2/3 ?= True
print("Is", f3, " >= ", f2, "?=", f3 >= f2) # Is 2/3 >= -3/4 ?= True
print("Is", f3, " != ", f2, "?=", f3 != f2) # Is 2/3 != -3/4 ?= True
print(f3, "=", "{:.2f}".format(round(float(f3), 2)), "=", round(float(f3)*100, 2), "%") # 2/3 = 0.67 = 66.67 %
f4 = Fraction(1, 3)
print(f4, "=", "{:.2f}".format(round(float(f4), 2)), "=", round(float(f4)*100, 2), "%") # 1/3 = 0.33 = 33.33 %
if __name__ == '__main__':
main()
```