Implementing FixedPoint reflected operators

Reflected operators are used in the following two cases:

  • The right-hand operand is a subclass of the left-hand operand. In this case, the reflected operator is tried first to ensure that the subclass overrides the parent class.
  • The left-hand operand's class doesn't implement the special method required. In this case, the right-hand operand's reflected special method is used.

The following table shows the mapping between reflected special methods and operators:

Method

Operator

object.__radd__(self, other)

+

object.__rsub__(self, other)

-

object.__rmul__(self, other)

*

object.__rtruediv__(self, other)

/

object.__rfloordiv__(self, other)

//

object.__rmod__(self, other)

%

object.__rdivmod__(self, other)

divmod()

object.__rpow__(self, other[, modulo])

pow() as well as **

 

These reflected operation special methods are also built around a common boilerplate. Since these are reflected, the order of the operands in subtraction, division, modulus, and power is important. For commutative operations, such as addition and multiplication, the order doesn't matter. The following are the implementations for the reflected operators:

def __radd__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_scale = self.scale
new_value = other * self.scale + self.value
else:
new_scale = max(self.scale, other.scale)
new_value = other.value * (new_scale // other.scale) + self.value * (
new_scale // self.scale
)
return FixedPoint(int(new_value), scale=new_scale)

def __rsub__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_scale = self.scale
new_value = other * self.scale - self.value
else:
new_scale = max(self.scale, other.scale)
new_value = other.value * (new_scale // other.scale) - self.value * (
new_scale // self.scale
)
return FixedPoint(int(new_value), scale=new_scale)

def __rmul__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_scale = self.scale
new_value = other * self.value
else:
new_scale = self.scale * other.scale
new_value = other.value * self.value
return FixedPoint(int(new_value), scale=new_scale)

def __rtruediv__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_value = self.scale * int(other / (self.value / self.scale))
else:
new_value = int((other.value / other.scale) / self.value)
return FixedPoint(new_value, scale=self.scale)

def __rfloordiv__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_value = self.scale * int(other // (self.value / self.scale))
else:
new_value = int((other.value / other.scale) // self.value)
return FixedPoint(new_value, scale=self.scale)

def __rmod__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_value = other % (self.value / self.scale)
else:
new_value = (other.value / other.scale) % (self.value / self.scale)
return FixedPoint(new_value, scale=self.scale)

def __rpow__(self, other: Union['FixedPoint', int]) -> 'FixedPoint':
if not isinstance(other, FixedPoint):
new_value = other ** (self.value / self.scale)
else:
new_value = (other.value / other.scale) ** self.value / self.scale
return FixedPoint(int(new_value) * self.scale, scale=self.scale)

We've tried to use math that is identical to the forward operators. The idea is to switch the operands in a simple way. This follows from the most common situation. Having the text of the forward and reverse methods match each other simplifies code inspections, and yes, there is some redundancy in the commutative operator implementations.

As with the forward operators, we've kept the division, modulus, and power operators simple to avoid optimizations. The versions shown here can introduce noise from the conversion to a floating-point approximation and back to a FixedPoint value. In the next section, we'll see how to implement FixedPoint comparison operators.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset