code: def mul(self, o):
          
          if self.is_integer and o.is_integer:
              # Two integers!
              a, b = self.lower_bound, o.lower_bound
              ret = StridedInterval(bits=self.bits,
                                    stride=0,
                                    lower_bound=a * b,
                                    upper_bound=a * b
                                    )
  
              if a * b > (2 ** self.bits - 1):
                  logger.warning('Overflow in multiplication detected.')
  
              return ret.normalize()
  
          else:
              # All other cases
  
              # Cut from both north pole and south pole
              si1_psplit = self._psplit()
              si2_psplit = o._psplit()
              all_resulting_intervals = list()
  
              for si1 in si1_psplit:
                  for si2 in si2_psplit:
                      tmp_unsigned_mul = self._wrapped_unsigned_mul(si1, si2)
                      tmp_signed_mul = self._wrapped_signed_mul(si1, si2)
                      for tmp_meet in tmp_unsigned_mul._multi_valued_intersection(tmp_signed_mul):
                          all_resulting_intervals.append(tmp_meet)
          return StridedInterval.least_upper_bound(*all_resulting_intervals).normalize()
docs: Binary operation: multiplication
  
          :param o: The other operand
          :return: self * o