1"""compatibility layer for decimal (Python standard library)""" 2from __future__ import absolute_import 3from decimal import * 4 5 6try: 7 Decimal.from_float # New in 2.7 8except AttributeError: 9 import math as _math 10 11 def _bit_length(integer): 12 s = bin(integer) # binary representation: bin(-37) --> '-0b100101' 13 s = s.lstrip('-0b') # remove leading zeros and minus sign 14 return len(s) # len('100101') --> 6 15 16 @classmethod 17 def _from_float(cls, f): 18 if isinstance(f, int): # handle integer inputs 19 return cls(f) 20 if not isinstance(f, float): 21 raise TypeError("argument must be int or float.") 22 if _math.isinf(f) or _math.isnan(f): 23 return cls(repr(f)) 24 if _math.copysign(1.0, f) == 1.0: 25 sign = 0 26 else: 27 sign = 1 28 n, d = abs(f).as_integer_ratio() 29 #k = d.bit_length() - 1 30 k = _bit_length(d) - 1 31 result = _dec_from_triple(sign, str(n*5**k), -k) 32 if cls is Decimal: 33 return result 34 else: 35 return cls(result) 36 37 Decimal.from_float = _from_float 38 39 40if Decimal('1.0') != 1.0: # Changed in Python 3.2 41 42 import numbers as _numbers 43 from decimal import _dec_from_triple 44 45 46 class FloatOperation(DecimalException, TypeError): 47 """Enable stricter semantics for mixing floats and Decimals.""" 48 pass 49 50 51 # Adapted from Python 3.1 standard library. 52 _context_init_orig = Context.__init__ 53 def _context_init_new(self, prec=None, rounding=None, 54 traps=None, flags=None, 55 Emin=None, Emax=None, 56 capitals=None, _clamp=0, 57 _ignored_flags=None): 58 59 # Call original __init__. 60 _context_init_orig(self, prec=prec, rounding=rounding, traps=traps, 61 flags=flags, Emin=Emin, Emax=Emax, capitals=capitals, 62 _clamp=_clamp, _ignored_flags=_ignored_flags) 63 64 # Add FloatOperation to `traps` dict. 65 self.traps[FloatOperation] = 0 66 67 Context.__init__ = _context_init_new 68 69 70 # Adapted from Python 3.4 standard library. 71 def _convert_for_comparison(self, other, equality_op=False): 72 if isinstance(other, Decimal): 73 return self, other 74 if isinstance(other, _numbers.Rational): 75 if not self._is_special: 76 self = _dec_from_triple(self._sign, 77 str(int(self._int) * other.denominator), 78 self._exp) 79 return self, Decimal(other.numerator) 80 if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0: 81 other = other.real 82 if isinstance(other, float): 83 context = getcontext() 84 if equality_op: 85 context.flags[FloatOperation] = 1 86 else: 87 context._raise_error(FloatOperation, 88 "strict semantics for mixing floats and Decimals are enabled") 89 return self, Decimal.from_float(other) 90 return NotImplemented, NotImplemented 91 92 def _eq(self, other, context=None): 93 self, other = _convert_for_comparison(self, other, equality_op=True) 94 if other is NotImplemented: 95 return other 96 if self._check_nans(other, context): 97 return False 98 return self._cmp(other) == 0 99 Decimal.__eq__ = _eq 100 101 def _ne(self, other, context=None): 102 self, other = _convert_for_comparison(self, other, equality_op=True) 103 if other is NotImplemented: 104 return other 105 if self._check_nans(other, context): 106 return True 107 return self._cmp(other) != 0 108 Decimal.__ne__ = _ne 109 110 def _lt(self, other, context=None): 111 self, other = _convert_for_comparison(self, other) 112 if other is NotImplemented: 113 return other 114 ans = self._compare_check_nans(other, context) 115 if ans: 116 return False 117 return self._cmp(other) < 0 118 Decimal.__lt__ = _lt 119 120 def _le(self, other, context=None): 121 self, other = _convert_for_comparison(self, other) 122 if other is NotImplemented: 123 return other 124 ans = self._compare_check_nans(other, context) 125 if ans: 126 return False 127 return self._cmp(other) <= 0 128 Decimal.__le__ = _le 129 130 def _gt(self, other, context=None): 131 self, other = _convert_for_comparison(self, other) 132 if other is NotImplemented: 133 return other 134 ans = self._compare_check_nans(other, context) 135 if ans: 136 return False 137 return self._cmp(other) > 0 138 Decimal.__gt__ = _gt 139 140 def _ge(self, other, context=None): 141 self, other = _convert_for_comparison(self, other) 142 if other is NotImplemented: 143 return other 144 ans = self._compare_check_nans(other, context) 145 if ans: 146 return False 147 return self._cmp(other) >= 0 148 Decimal.__ge__ = _ge 149