code: def add(self, b):
          
          new_bits = max(self.bits, b.bits)
  
          # TODO: Some improvements can be made here regarding the following case
          # TODO: SI<16>0xff[0x0, 0xff] + 3
          # TODO: In current implementation, it overflows, but it doesn't have to
  
          # optimization
          # case: SI<16>0xff[0x0, 0xff] + 3
          """
          if self.is_top and b.is_integer:
              si = self.copy()
              si.lower_bound = b.lower_bound
              return si
          elif b.is_top and self.is_integer:
              si = b.copy()
              si.lower_bound = self.lower_bound
              return si
          """
          #FIXME
  
          overflow = self._wrapped_overflow_add(self, b)
          if overflow:
              return StridedInterval.top(self.bits)
  
          lb = self._modular_add(self.lower_bound, b.lower_bound, new_bits)
          ub = self._modular_add(self.upper_bound, b.upper_bound, new_bits)
  
          # Is it initialized?
          uninitialized = self.uninitialized or b.uninitialized
  
          # Take the GCD of two operands' strides
          stride = fractions.gcd(self.stride, b.stride)
  
          return StridedInterval(bits=new_bits, stride=stride, lower_bound=lb, upper_bound=ub,
                                 uninitialized=uninitialized).normalize()
docs: Binary operation: add
  
          :param b: The other operand
          :return: self + b