Emulating Numeric Types in Python


Python includes built-in mathematical data structures like complex numbers, floating-point numbers, and integers. But occasionally we might want to develop our own custom-behaved number classes. Here, the idea of imitating number classes is put into use. We can create objects that can be used in the same way as native numeric classes by simulating them. We will look at how to simulate numeric classes in Python in this article.

Example 1: Emulating Addition

class MyNumber:
   def __init__(self, x):
      self.x = x
   def __add__(self, other):
      return MyNumber(self.x + other.x)
a = MyNumber(2)
b = MyNumber(3)
c = a + b
print(c.x)

Output

5

Here, we define a custom class MyNumber that takes a value x as input. Then the __add__ method, which is called when the + operator is used between two instances of MyNumber. This method returns a new instance of MyNumber with the sum of the two input values

Example 2: Emulating Comparison

class MyNumber:
   def __init__(self, x):
      self.x = x
   def __eq__(self, other):
      return self.x == other.x
a = MyNumber(2)
b = MyNumber(3)
c = MyNumber(2)
print(a == b)
print(a == c)

Output

False
True

A custom class MyNumber that takes a value x as input. We then define the __eq__ method, which is called when the == operator is used between two instances of MyNumber. This method returns True if the values of the two instances are equal, and False otherwise.

Emulating Fractions as a Numeric Type

Let's examine a more thorough illustration of a number type. To symbolize a fraction as a numerator and a denominator, create a class called Fraction. Then add numeric type support with arithmetic operations like add, remove, multiply, divide, as well as how to compare numbers.

Example

class Fraction:
   def __init__(self, num, deno=1):
      self.num = num
      self.deno = deno
   def __str__(self):
      if self.deno == 1:
         return str(self.num)
      else:
         return "{}/{}".format(self.num, self.deno)
   def __add__(self, other):
      if isinstance(other, int):
         other = Fraction(other)
      common_deno = self.deno * other.deno
      num = self.num * other.deno + other.num * self.deno
      return Fraction(num, common_deno).simplify()
   def __sub__(self, other):
      if isinstance(other, int):
         other = Fraction(other)
      common_deno = self.deno * other.deno
      num = self.num * other.deno - other.num * self.deno
      return Fraction(num, common_deno).simplify()
   def __mul__(self, other):
      if isinstance(other, int):
         other = Fraction(other)
      num = self.num * other.nu
      deno = self.deno * other.deno
      return Fraction(num, deno).simplify()
   def __truediv__(self, other):
      if isinstance(other, int):
         other = Fraction(other)
      if isinstance(other, float):
         return float(self.num / self.deno) / other
      num = self.num * other.deno
      deno = self.deno * other.num
      return Fraction(num, deno)
   def gcd(self, a, b):
      if b == 0:
         return a
      else:
         return self.gcd(b, a % b)
   def simplify(self):
      divisor = self.gcd(self.num, self.deno)
      num = self.num // divisor
      deno = self.deno // divisor
      if deno < 0:
         num = -num
         deno = -deno
      return Fraction(num, deno)
      
# Create some Fraction objects
f1 = Fraction(2, 3)
f2 = Fraction(3, 4)
f3 = Fraction(1, 2)

# Perform some operations
print(f1 + f2) 
print(f2 - f3) 
print(f1 * f3) 
print(f1 / f2) 

Output

17/12
1/4
1/3
8/9

The Fraction class is a nifty way to perform arithmetic operations on Fraction objects. We'll define the init, str, add, sub, mul, and truediv methods to handle arithmetic. In addition, we'll define two helper methods, gcd and simplify, which help us reduce fractions to their simplest form.

After making three Fraction objects with various numbers, f1, f2, and f3 - the +, -, *, and / operators can be used to conduct a wide range of actions on these objects, and the outcomes can then be printed. It's important to note that the truediv function accepts any form of operand, including floating-point numbers, integers, and fractional objects. It gives a float result if the other is a float, and a fraction result if it is not. Therefore, we can use formulas like f1 / 2.0 or f2 / f3 without risk and anticipate a div outcome.

Applications

  • Implementing specialized numerical types with specific behavior, such as fractions or complex numbers, is one use for emulating numeric categories.

  • Employing more effective data structures and methods to increase the efficiency of numerical calculations.

  • Giving numerical processes a more descriptive and understandable vocabulary will make code easier to comprehend and manage.

Conclusion

By simulating numeric types in Python, it is possible to build unique numerical types with specialized and tailored behavior, enhance calculation speed, and make their code easier to understand and manage. To specify how objects of their custom types act when subjected to arithmetic operations use “magic methods” or “dunder methods” such as __add__, __sub__, and __truediv__. All of these allow you to override the default behavior in a way that you want in order to mimic numeric type operations on any class or object of choice.

Updated on: 18-Apr-2023

313 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements