예제 #1
0
def _add(a, b):
    assert isinstance(a, FixedPoint)
    assert isinstance(b, FixedPoint)
    promoted_qformat = QFormat.from_qformats(a.qformat, b.qformat)
    result_qformat = QFormat(promoted_qformat.integer_bits + 1,
                             promoted_qformat.fraction_bits)
    lhs_op = FixedPoint(a, result_qformat)
    rhs_op = FixedPoint(b, result_qformat)
    result_numerator = lhs_op._numerator + rhs_op._numerator
    return FixedPoint._from_numerator(result_numerator, result_qformat)
예제 #2
0
def _add(a, b):
    assert isinstance(a, FixedPoint)
    assert isinstance(b, FixedPoint)
    promoted_qformat = QFormat.from_qformats(a.qformat, b.qformat)
    result_qformat = QFormat(promoted_qformat.integer_bits + 1, promoted_qformat.fraction_bits)
    lhs_op = FixedPoint(a, result_qformat)
    rhs_op = FixedPoint(b, result_qformat)
    result_numerator = lhs_op._numerator + rhs_op._numerator
    return FixedPoint._from_numerator(result_numerator, result_qformat)
예제 #3
0
def _truediv(dividend, divisor):
    assert isinstance(dividend, FixedPoint)
    assert isinstance(divisor, FixedPoint)
    result_qformat = QFormat(
        dividend.qformat.integer_bits + divisor.qformat.fraction_bits + 1,
        divisor.qformat.integer_bits + dividend.qformat.fraction_bits)

    working_qformat = QFormat.from_qformats(dividend.qformat, divisor.qformat,
                                            result_qformat)

    lhs_op = FixedPoint(dividend, working_qformat)
    rhs_op = FixedPoint(divisor, working_qformat)

    # We use Fraction's round() here rather than floor division to get correct rounding
    working_numerator = round(
        Fraction(lhs_op._numerator * working_qformat.denominator,
                 rhs_op._numerator))
    working_result = FixedPoint._from_numerator(working_numerator,
                                                working_qformat)
    return FixedPoint(working_result, result_qformat)
예제 #4
0
def _mul(a, b):
    assert isinstance(a, FixedPoint)
    assert isinstance(b, FixedPoint)
    result_qformat = QFormat(
        a.qformat.integer_bits + b.qformat.integer_bits + 1,
        a.qformat.fraction_bits + b.qformat.fraction_bits)
    lhs_op = FixedPoint(a, result_qformat)
    rhs_op = FixedPoint(b, result_qformat)
    result_numerator = (lhs_op._numerator *
                        rhs_op._numerator) // result_qformat.denominator
    return FixedPoint._from_numerator(result_numerator, result_qformat)
예제 #5
0
    def _from_integer(cls, i):
        """Create a FixedPoint using a QFormat with sufficient precision to represent the integer.

        Args:
            i: The integer to be represented in FixedPoint.

        Returns:
            A FixedPoint representation with sufficient precision to represent i.
        """
        assert isinstance(i, int)
        num_bits = i.bit_length() + 1  # Additional bit for sign information
        qformat = QFormat(num_bits, 0)
        return cls._from_numerator(i, qformat)
예제 #6
0
def _truediv(dividend, divisor):
    assert isinstance(dividend, FixedPoint)
    assert isinstance(divisor, FixedPoint)
    result_qformat = QFormat(dividend.qformat.integer_bits + divisor.qformat.fraction_bits + 1,
                             divisor.qformat.integer_bits + dividend.qformat.fraction_bits)

    working_qformat = QFormat.from_qformats(dividend.qformat, divisor.qformat, result_qformat)

    lhs_op = FixedPoint(dividend, working_qformat)
    rhs_op = FixedPoint(divisor, working_qformat)

    # We use Fraction's round() here rather than floor division to get correct rounding
    working_numerator = round(Fraction(lhs_op._numerator * working_qformat.denominator,  rhs_op._numerator))
    working_result = FixedPoint._from_numerator(working_numerator, working_qformat)
    return FixedPoint(working_result, result_qformat)
예제 #7
0
def _pow(base, exponent):
    assert isinstance(base, FixedPoint)
    assert isinstance(base, FixedPoint)
    if exponent.is_integer():
        integer_exponent = abs(floor(exponent))
        result_qformat = QFormat(
            max(base.qformat.integer_bits - 1, 0) * integer_exponent + 1,
            base.qformat.fraction_bits * integer_exponent)
        result_numerator = base._numerator**integer_exponent
        positive_result = FixedPoint._from_numerator(result_numerator,
                                                     result_qformat)
        if exponent >= 0:
            return positive_result
        else:
            reciprocal_result = 1 / positive_result
            return reciprocal_result
    return float(base)**float(exponent)
예제 #8
0
    def _from_float(cls, f):
        """Create a FixedPoint using a QFormat without loss of precision.

        Args:
            f (float): A float of which to create an equivalent FixedPoint representation.

        Returns:
            A FixedPoint object the QFormat for which will have sufficient precision to
            exactly represent the float.

        Raises:
            OverflowError: If f is NaN or infinite.
        """
        assert isinstance(f, Real)
        if isnan(f) or isinf(f):
            raise OverflowError("{} cannot be represented by {}".format(
                f, cls.__name__))

        # 1. Work out where the binary point is
        fr, exp = frexp(f)
        numerator = int(fr * (2**53))  # 53 binary places in the fraction
        binary_point_index = 53 - exp  # Is one based

        # 2. Work out how many significant figures there are to the left of the binary point; call this m
        most_significant_set_index = numerator.bit_length() - 1
        num_leading_bits = 1 + most_significant_set_index - binary_point_index
        m = max(num_leading_bits, 0) + 1  # One to accommodate sign

        # 3. Work out how many significant figures there are to the right of the binary point; call this n
        lowest_bit = lowest_set_bit(numerator)
        least_significant_set_index = lowest_bit.bit_length() - 1
        num_trailing_bits = binary_point_index - least_significant_set_index
        n = max(num_trailing_bits, 0)

        # 4. Make QFormat(m, n)
        qformat = QFormat(m, n)

        # 5. Shift the numerator to fit Qm.n
        #    We want the binary point to be at index n
        shift = binary_point_index - n
        shifted_numerator = signed_left_shift(numerator, shift)

        return cls._from_numerator(shifted_numerator, qformat)
예제 #9
0
    def _from_rational_exact(cls, r):
        """Create a FixedPoint using a QFormat with sufficient precision to represent the integer.

        Args:
            r: A rational number to be represented exactly.

        Returns:
            An exact FixedPoint representation of r.

        Raises:
            ValueError: If r cannot be represented exactly.
        """
        assert isinstance(r, Rational)
        integer_part = trunc(r)
        fraction_part = abs(r - integer_part)
        binary_numerator, binary_denominator = fraction_with_base(
            fraction_part, base=2)
        qformat = QFormat(integer_part.bit_length() + 1,
                          int(log2(binary_denominator)))
        return cls._from_numerator(binary_numerator, qformat)
예제 #10
0
 def __neg__(self):
     # This can overflow for the most negative value of the current QFormat - the positive value can't be
     # represented - so the result must have one additional bit of precision.
     result_qformat = QFormat(self._qformat.integer_bits + 1,
                              self._qformat.fraction_bits)
     return FixedPoint._from_numerator(-self._numerator, result_qformat)