def check_ulpdiff(self, exact, rounded):
        # current precision
        p = context.d.prec

        # Convert infinities to the largest representable number + 1.
        x = exact
        if exact.is_infinite():
            x = decimal._dec_from_triple(exact._sign, '10', context.d.Emax)
        y = rounded
        if rounded.is_infinite():
            y = decimal._dec_from_triple(rounded._sign, '10', context.d.Emax)

        # err = (rounded - exact) / ulp(rounded)
        self.maxctx.prec = p * 2
        t = self.maxctx.subtract(y, x)
        if context.f._flags & cdecimal.DecClamped or \
           context.f._flags & cdecimal.DecUnderflow:
            # The standard ulp does not work in Underflow territory.
            ulp = self.harrison_ulp(y)
        else:
            ulp = self.standard_ulp(y, p)
        # Error in ulps.
        err = self.maxctx.divide(t, ulp)

        d = decimal
        dir = self.rounding_direction(x, context.d.rounding)
        if dir == 0:
            if d.Decimal("-0.6") < err < d.Decimal("0.6"):
                return True
        elif dir == 1: # directed, upwards
            if d.Decimal("-0.1") < err < d.Decimal("1.1"):
                return True
        elif dir == -1: # directed, downwards
            if d.Decimal("-1.1") < err < d.Decimal("0.1"):
                return True
        else: # ROUND_05UP
            if d.Decimal("-1.1") < err < d.Decimal("1.1"):
                return True

        print("ulp: %s  error: %s  exact: %s  mpd_rounded: %s"
              % (ulp, err, exact, rounded))
        return False
Beispiel #2
0
def from_float_26(f):
    """Converts a float to a decimal number, exactly.

    Note that Decimal.from_float(0.1) is not the same as Decimal('0.1').
    Since 0.1 is not exactly representable in binary floating point, the
    value is stored as the nearest representable value which is
    0x1.999999999999ap-4.  The exact equivalent of the value in decimal
    is 0.1000000000000000055511151231257827021181583404541015625.

    >>> Decimal.from_float(0.1)
    Decimal('0.1000000000000000055511151231257827021181583404541015625')
    >>> Decimal.from_float(float('nan'))
    Decimal('NaN')
    >>> Decimal.from_float(float('inf'))
    Decimal('Infinity')
    >>> Decimal.from_float(-float('inf'))
    Decimal('-Infinity')
    >>> Decimal.from_float(-0.0)
    Decimal('-0')

    """
    import math as _math
    from decimal import _dec_from_triple  # only available on Py2.6 and Py2.7 (not 3.3)

    if isinstance(f, (int, long)):  # handle integer inputs
        return Decimal(f)
    if _math.isinf(f) or _math.isnan(f):  # raises TypeError if not a float
        return Decimal(repr(f))
    if _math.copysign(1.0, f) == 1.0:
        sign = 0
    else:
        sign = 1
    n, d = abs(f).as_integer_ratio()

    # int.bit_length() method doesn't exist on Py2.6:
    def bit_length(d):
        if d != 0:
            return len(bin(abs(d))) - 2
        else:
            return 0

    k = bit_length(d) - 1
    result = _dec_from_triple(sign, str(n * 5**k), -k)
    return result
Beispiel #3
0
 def _from_float(cls, f):
     if isinstance(f, int):                # handle integer inputs
         return cls(f)
     if not isinstance(f, float):
         raise TypeError("argument must be int or float.")
     if _math.isinf(f) or _math.isnan(f):
         return cls(repr(f))
     if _math.copysign(1.0, f) == 1.0:
         sign = 0
     else:
         sign = 1
     n, d = abs(f).as_integer_ratio()
     #k = d.bit_length() - 1
     k = _bit_length(d) - 1
     result = _dec_from_triple(sign, str(n*5**k), -k)
     if cls is Decimal:
         return result
     else:
         return cls(result)
Beispiel #4
0
 def _from_float(cls, f):
     if isinstance(f, int):  # handle integer inputs
         return cls(f)
     if not isinstance(f, float):
         raise TypeError("argument must be int or float.")
     if _math.isinf(f) or _math.isnan(f):
         return cls(repr(f))
     if _math.copysign(1.0, f) == 1.0:
         sign = 0
     else:
         sign = 1
     n, d = abs(f).as_integer_ratio()
     #k = d.bit_length() - 1
     k = _bit_length(d) - 1
     result = _dec_from_triple(sign, str(n * 5**k), -k)
     if cls is Decimal:
         return result
     else:
         return cls(result)
Beispiel #5
0
def from_float_26(f):
    """Converts a float to a decimal number, exactly.

    Note that Decimal.from_float(0.1) is not the same as Decimal('0.1').
    Since 0.1 is not exactly representable in binary floating point, the
    value is stored as the nearest representable value which is
    0x1.999999999999ap-4.  The exact equivalent of the value in decimal
    is 0.1000000000000000055511151231257827021181583404541015625.

    >>> Decimal.from_float(0.1)
    Decimal('0.1000000000000000055511151231257827021181583404541015625')
    >>> Decimal.from_float(float('nan'))
    Decimal('NaN')
    >>> Decimal.from_float(float('inf'))
    Decimal('Infinity')
    >>> Decimal.from_float(-float('inf'))
    Decimal('-Infinity')
    >>> Decimal.from_float(-0.0)
    Decimal('-0')

    """
    import math as _math
    from decimal import _dec_from_triple    # only available on Py2.6 and Py2.7 (not 3.3)

    if isinstance(f, (int, long)):        # handle integer inputs
        return Decimal(f)
    if _math.isinf(f) or _math.isnan(f):  # raises TypeError if not a float
        return Decimal(repr(f))
    if _math.copysign(1.0, f) == 1.0:
        sign = 0
    else:
        sign = 1
    n, d = abs(f).as_integer_ratio()
    # int.bit_length() method doesn't exist on Py2.6:
    def bit_length(d):
        if d != 0:
            return len(bin(abs(d))) - 2
        else:
            return 0
    k = bit_length(d) - 1
    result = _dec_from_triple(sign, str(n*5**k), -k)
    return result
Beispiel #6
0
 def _convert_for_comparison(self, other, equality_op=False):
     if isinstance(other, Decimal):
         return self, other
     if isinstance(other, _numbers.Rational):
         if not self._is_special:
             self = _dec_from_triple(self._sign,
                                     str(int(self._int) * other.denominator),
                                     self._exp)
         return self, Decimal(other.numerator)
     if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0:
         other = other.real
     if isinstance(other, float):
         context = getcontext()
         if equality_op:
             context.flags[FloatOperation] = 1
         else:
             context._raise_error(FloatOperation,
                 "strict semantics for mixing floats and Decimals are enabled")
         return self, Decimal.from_float(other)
     return NotImplemented, NotImplemented
Beispiel #7
0
 def _convert_for_comparison(self, other, equality_op=False):
     if isinstance(other, Decimal):
         return self, other
     if isinstance(other, _numbers.Rational):
         if not self._is_special:
             self = _dec_from_triple(
                 self._sign, str(int(self._int) * other.denominator),
                 self._exp)
         return self, Decimal(other.numerator)
     if equality_op and isinstance(other,
                                   _numbers.Complex) and other.imag == 0:
         other = other.real
     if isinstance(other, float):
         context = getcontext()
         if equality_op:
             context.flags[FloatOperation] = 1
         else:
             context._raise_error(
                 FloatOperation,
                 "strict semantics for mixing floats and Decimals are enabled"
             )
         return self, Decimal.from_float(other)
     return NotImplemented, NotImplemented
Beispiel #8
0
 def standard_ulp(self, dec, prec):
     return P._dec_from_triple(0, '1', dec._exp + len(dec._int) - prec)
    def __add__(self, other, context=None):
        """Returns self + other.

        -INF + INF (or the reverse) cause InvalidOperation errors.
        """
        other = _convert_other(other)
        if other is NotImplemented:
            return other

        if context is None:
            context = _getcontext()

        if self._is_special or other._is_special:
            ans = self._check_nans(other, context)
            if ans:
                return ans

            if self._isinfinity():
                # If both INF, same sign => same as both, opposite => error.
                if self._sign != other._sign and other._isinfinity():
                    return context._raise_error(InvalidOperation, '-INF + INF')
                return _Decimal(self)
            if other._isinfinity():
                return _Decimal(other)  # Can't both be infinity here

        exp = min(self._exp, other._exp)
        negativezero = 0
        if context.rounding == 'ROUND_FLOOR' and self._sign != other._sign:
            # If the answer is 0, the sign should be negative, in this case.
            negativezero = 1

        if not self and not other:
            sign = min(self._sign, other._sign)
            if negativezero:
                sign = 1
            ans = _dec_from_triple(sign, '0', exp)
            ans = ans._fix(context)
            return ans
        if not self:
            exp = max(exp, other._exp - context.prec - 1)
            ans = other._rescale(exp, context.rounding)
            ans = ans._fix(context)
            return ans
        if not other:
            exp = max(exp, self._exp - context.prec - 1)
            ans = self._rescale(exp, context.rounding)
            ans = ans._fix(context)
            return ans

        op1 = decimal._WorkRep(self)
        op2 = decimal._WorkRep(other)
        op1, op2 = decimal._normalize(op1, op2, context.prec)

        result = decimal._WorkRep()
        if op1.sign != op2.sign:
            # Equal and opposite
            if op1.int == op2.int:
                ans = decimal._dec_from_triple(negativezero, '0', exp)
                ans = ans._fix(context)
                return ans
            if op1.int < op2.int:
                op1, op2 = op2, op1
                # OK, now abs(op1) > abs(op2)
            if op1.sign == 1:
                result.sign = 1
                op1.sign, op2.sign = op2.sign, op1.sign
            else:
                result.sign = 0
                # So we know the sign, and op1 > 0.
        elif op1.sign == 1:
            result.sign = 1
            op1.sign, op2.sign = (0, 0)
        else:
            result.sign = 0
        # Now, op1 > abs(op2) > 0

        if op2.sign == 0:
            result.int = op1.int + op2.int
        else:
            result.int = op1.int - op2.int

        result.exp = op1.exp
        ans = _Decimal(result)
        ans = ans._fix(context)
        return Nbr(ans)
Beispiel #10
0
 def standard_ulp(self, dec, prec):
     return P._dec_from_triple(0, '1', dec._exp+len(dec._int)-prec)