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
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
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)
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)
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
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
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
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)
def standard_ulp(self, dec, prec): return P._dec_from_triple(0, '1', dec._exp+len(dec._int)-prec)