예제 #1
0
 def multiply(self, x, y):
     # Use 2 * wordlength long multipliers
     z = Representation(mantissa=x.mantissa * y.mantissa,
                        format_=Format(msb=self.format_.msb * 2 + 1,
                                       lsb=self.format_.lsb * 2,
                                       signed=self.format_.signed))
     mantissa, (underflow, overflow) = self.format_.represent(
         z, rounding_method=self.rounding_method)
     if underflow and not self.multiply.allows_underflow:
         raise UnderflowError(f'{x} * {y} underflows in {self.format_}',
                              mpfloat(z), self.format_.value_epsilon)
     if overflow:
         if not self.multiply.allows_overflow:
             raise OverflowError(f'{x} * {y} overflows in {self.format_}',
                                 mpfloat(z), self.format_.value_interval)
         mantissa, _ = self.overflow_behavior(
             mantissa, range_=self.format_.mantissa_interval)
     return type(x)(mantissa, self.format_)
예제 #2
0
파일: symbolic.py 프로젝트: hidmic/ltitop
 def __le__(self, other):
     if not other.is_Number:
         return super().__le__(other)
     if not other:
         return self._args[0] <= 0
     if isinstance(other, type(self)):
         return self._args[0] <= other._args[0]
     if isinstance(self._args[0], Basic):
         return self._args[0] <= other
     return self._args[0] <= mpfloat(other)
예제 #3
0
파일: symbolic.py 프로젝트: hidmic/ltitop
 def __eq__(self, other):
     if not other.is_Number:
         return False
     if not other:
         return not self._args[0]
     if isinstance(other, type(self)):
         return self._args[0] == other._args[0]
     if isinstance(self._args[0], Basic):
         return self._args[0] == other
     return self._args[0] == mpfloat(other)
예제 #4
0
 def computation_error_bounds(self, input_range, state_ranges=None):
     if state_ranges is None and self.states:
         state_ranges = []
         for model in self.state_observer_models:
             state_range = output_range(model, mpfloat(input_range))
             state_range = interval(
                 lower_bound=asvector_if_possible(state_range.lower_bound),
                 upper_bound=asvector_if_possible(state_range.upper_bound),
             )
             state_ranges.append(state_range)
     return super().computation_error_bounds([input_range], state_ranges)
예제 #5
0
 def nearest(self, x):
     if x.is_integer:
         return x
     value = nearest_integer(mpfloat(x))
     mantissa, (_, overflow) = self.format_.represent(value)
     if overflow:
         if not self.nearest.allows_overflow:
             raise OverflowError(f'round({x}) overflows in {self.format_}',
                                 mantissa * self.format_.value_epsilon,
                                 self.format_.value_interval)
         mantissa, _ = self.overflow_behavior(
             mantissa, range_=self.format_.mantissa_interval)
     return type(x)(mantissa, format_)
예제 #6
0
 def __mul__(self, other):
     if not isinstance(other, Number):
         other = Number(other)
     result = self.number * other.number
     snumber = mpfloat(self.number)
     onumber = mpfloat(other.number)
     result_error_bounds = ((snumber + self.error_bounds) *
                            (onumber + other.error_bounds)).difference(
                                snumber * onumber)
     if isinstance(result, (FixedPointNumber, FixedPointSymbol)):
         exact = (self.number == -1 or self.number == 1 or self.number == 0
                  or other.number == -1 or other.number == 1
                  or other.number == 0)
         if not exact:
             rounding = ProcessingUnit.active().rounding_method
             if isinstance(self.number, (FixedPointNumber, FixedPointSymbol)) and \
                isinstance(other.number, (FixedPointNumber, FixedPointSymbol)):
                 result_error_bounds += rounding.error_bounds(
                     result.format_.lsb,
                     self.number.format_.lsb + other.number.format_.lsb)
             else:
                 result_error_bounds += rounding.error_bounds(
                     result.format_.lsb)
     return Number(result, result_error_bounds)
예제 #7
0
파일: formats.py 프로젝트: hidmic/ltitop
 def represent(self, rvalue, rounding_method=round):
     from ltitop.arithmetic.fixed_point.representation import Representation
     if isinstance(rvalue, Representation) and hasattr(
             rounding_method, 'shift'):
         lvalue = rvalue.mantissa
         quantize = functools.partial(rounding_method.shift,
                                      n=rvalue.format_.lsb - self.lsb)
     else:
         lvalue = mpfloat(rvalue)
         quantize = functools.partial(mpquantize,
                                      nbits=-self.lsb,
                                      rounding_method=rounding_method)
     if not self.signed and not np.all(lvalue >= 0):
         raise ValueError(f'Unsigned format cannot represent {rvalue}')
     mantissa = quantize(lvalue)
     underflow = bool(np.any(np.logical_and(mantissa == 0, lvalue != 0)))
     overflow = bool(np.any(mantissa not in self.mantissa_interval))
     return mantissa, (underflow, overflow)
예제 #8
0
파일: formats.py 프로젝트: hidmic/ltitop
 def best(cls,
          value,
          wordlength,
          rounding_method=nearest_integer,
          signed=True):
     """
     See "Reliable Implementation of Linear Filters with Fixed-Point Arithmetic",
     Hilaire and Lopez, 2013
     """
     # TODO(hidmic): optimize when value is a Representation
     with mpmath.workprec(20 * wordlength):  # enough bits
         mpvalue = mpfloat(value)
         if not np.all(mpvalue >= 0) and not signed:
             raise ValueError(f'Unsigned format cannot represent {value}')
         # estimate MSB
         msb = np.max(mpmsb(mpvalue, signed=signed))
         if np.isneginf(msb):
             msb = 0  # arbitrary
         msb = int(msb)
         # estimate LSB
         lsb = msb - wordlength + int(signed)
         # compute mantissa
         mantissa = mpquantize(mpvalue,
                               nbits=-lsb,
                               rounding_method=rounding_method)
         # adjust MSB if limits were overpassed
         adjusted_msb = msb  # no adjustment
         upper_limit = 2**(wordlength - int(signed))
         if not np.all(mantissa < upper_limit):
             adjusted_msb = msb + 1
         if np.all(mantissa < 0):
             lower_limit = -2**(wordlength - 2)
             if np.all(mantissa > lower_limit):
                 adjusted_msb = msb - 1
         if adjusted_msb != msb:
             # adjust LSB and mantissa
             msb = adjusted_msb
             lsb = msb - wordlength + int(signed)
             mantissa = mpquantize(mpvalue,
                                   nbits=-lsb,
                                   rounding_method=mpmath.nint)
         return mantissa, cls(msb=msb, lsb=lsb, signed=signed)
예제 #9
0
파일: symbolic.py 프로젝트: hidmic/ltitop
 def _as_mpf_val(self, prec):
     with mpmath.workprec(prec):
         return mpfloat(self._args[0])
예제 #10
0
class Number:
    number: Any
    error_bounds: Interval = Interval(mpfloat(0))

    def __add__(self, other):
        if not isinstance(other, Number):
            other = Number(other)
        result = self.number + other.number
        result_error_bounds = self.error_bounds + other.error_bounds
        if isinstance(result, (FixedPointNumber, FixedPointSymbol)):
            exact = self.number == 0 or other.number == 0
            if not exact:
                rounding = ProcessingUnit.active().rounding_method
                if isinstance(self.number,
                              (FixedPointNumber, FixedPointSymbol)):
                    if result.format_.lsb > self.number.format_.lsb:
                        result_error_bounds += rounding.error_bounds(
                            result.format_.lsb, self.number.format_.lsb)
                elif self.number != 0:
                    result_error_bounds += rounding.error_bounds(
                        result.format_.lsb)
                if isinstance(other.number,
                              (FixedPointNumber, FixedPointSymbol)):
                    if result.format_.lsb > other.number.format_.lsb:
                        result_error_bounds += rounding.error_bounds(
                            result.format_.lsb, other.number.format_.lsb)
                elif other.number != 0:
                    result_error_bounds += rounding.error_bounds(
                        result.format_.lsb)
        return Number(result, result_error_bounds)

    __radd__ = __add__

    def __sub__(self, other):
        if not isinstance(other, Number):
            other = Number(other)
        result = self.number - other.number
        result_error_bounds = self.error_bounds + other.error_bounds
        if isinstance(result, (FixedPointNumber, FixedPointSymbol)):
            exact = self.number == 0 or other.number == 0
            if not exact:
                rounding = ProcessingUnit.active().rounding_method
                if isinstance(self.number,
                              (FixedPointNumber, FixedPointSymbol)):
                    if result.format_.lsb > self.number.format_.lsb:
                        result_error_bounds += rounding.error_bounds(
                            result.format_.lsb, self.number.format_.lsb)
                elif self.number != 0:
                    result_error_bounds += rounding.error_bounds(
                        result.format_.lsb)
                if isinstance(other.number,
                              (FixedPointNumber, FixedPointSymbol)):
                    if result.format_.lsb > other.number.format_.lsb:
                        result_error_bounds += rounding.error_bounds(
                            result.format_.lsb, other.number.format_.lsb)
                elif other.number != 0:
                    result_error_bounds += rounding.error_bounds(
                        result.format_.lsb)
        return Number(result, result_error_bounds)

    def __rsub__(self, other):
        return Number(other) - self

    def __mul__(self, other):
        if not isinstance(other, Number):
            other = Number(other)
        result = self.number * other.number
        snumber = mpfloat(self.number)
        onumber = mpfloat(other.number)
        result_error_bounds = ((snumber + self.error_bounds) *
                               (onumber + other.error_bounds)).difference(
                                   snumber * onumber)
        if isinstance(result, (FixedPointNumber, FixedPointSymbol)):
            exact = (self.number == -1 or self.number == 1 or self.number == 0
                     or other.number == -1 or other.number == 1
                     or other.number == 0)
            if not exact:
                rounding = ProcessingUnit.active().rounding_method
                if isinstance(self.number, (FixedPointNumber, FixedPointSymbol)) and \
                   isinstance(other.number, (FixedPointNumber, FixedPointSymbol)):
                    result_error_bounds += rounding.error_bounds(
                        result.format_.lsb,
                        self.number.format_.lsb + other.number.format_.lsb)
                else:
                    result_error_bounds += rounding.error_bounds(
                        result.format_.lsb)
        return Number(result, result_error_bounds)

    __rmul__ = __mul__

    def __div__(self, other):
        # TODO(hidmic): implement
        return NotImplemented

    __truediv__ = __div__

    def __rdiv__(self, other):
        return Number(other) / self

    __rtruediv__ = __rdiv__

    def __mod__(self, other):
        # TODO(hidmic): implement
        return NotImplemented

    def __rmod__(self, other):
        return Number(other) % self

    def __apply_rounding_method__(self, method):
        number = method(self.number)
        error_bounds = self.error_bounds
        lsb = None
        if isinstance(self.number, (FixedPointNumber, FixedPointSymbol)):
            lsb = self.number.format_.lsb
        error_bounds += method.error_bounds(0, lsb)
        return Number(number, error_bounds)

    def __trunc__(self):
        return self.__apply_rounding_method__(truncate)

    def __ceil__(self):
        return self.__apply_rounding_method__(ceil)

    def __floor__(self):
        return self.__apply_rounding_method__(floor)

    def __round__(self):
        return self.__apply_rounding_method__(nearest_integer)

    def __neg__(self):
        return Number(-self.number, -self.error_bounds)

    def __float__(self):
        return float(self.number)

    def __mpfloat__(self):
        return mpfloat(self.number)

    def __int__(self):
        return int(self.number)

    __long__ = __int__

    def __nonzero__(self):
        return bool(self.number)

    __bool__ = __nonzero__

    _iterable = False  # tell sympy to not iterate this

    def __getitem__(self, key):
        try:
            error_bounds = self.error_bounds[key]
        except TypeError:
            error_bounds = self.error_bounds
        return Number(self.number[key], error_bounds)

    def __eq__(self, other):
        if not isinstance(other, Number):
            other = Number(other)
        return self.number == other.number and \
            self.error_bounds == other.error_bounds == 0

    def __ne__(self, other):
        return not (self == other)

    def __lt__(self, other):
        if not isinstance(other, Number):
            other = Number(other)
        return mpfloat(self.number) + self.error_bounds < \
            mpfloat(other.number) + other.error_bounds

    def __le__(self, other):
        return self < other or self == other

    def __gt__(self, other):
        return not (self <= other)

    def __ge__(self, other):
        return not (self < other)

    def __lshift__(self, n):
        return Number(self.number << n, self.error_bounds * 2**n)

    def __rshift__(self, n):
        # TODO(hidmic): implement
        return NotImplemented
예제 #11
0
 def __lt__(self, other):
     if not isinstance(other, Number):
         other = Number(other)
     return mpfloat(self.number) + self.error_bounds < \
         mpfloat(other.number) + other.error_bounds
예제 #12
0
 def __mpfloat__(self):
     return mpfloat(self.number)