| 
          """ | 
        
        
           | 
          Simulation of binary floating point representation at arbitrary fixed or | 
        
        
           | 
          infinite precision (including greater than 64 bit). | 
        
        
           | 
          
 | 
        
        
           | 
          :name: Simfloat | 
        
        
           | 
          :author: Robert Clewley | 
        
        
           | 
          :version: 0.1 | 
        
        
           | 
          :contact: rob <dot> clewley <at> gmail <dot> com | 
        
        
           | 
          :date: August 2008 | 
        
        
           | 
          :license: New BSD | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ***** Features | 
        
        
           | 
          
 | 
        
        
           | 
          * Primarily intended for teaching purposes, e.g. in a numerical analysis course. | 
        
        
           | 
            Demonstrates representation formats and facilitates exploration of the | 
        
        
           | 
            distribution of represented values along the real number line. | 
        
        
           | 
          
 | 
        
        
           | 
          * Not intended to be the most efficient implementation, but transparency of | 
        
        
           | 
            implementation helpful for learning about issues in IEEE representation, e.g. | 
        
        
           | 
            denormalized numbers. | 
        
        
           | 
          
 | 
        
        
           | 
          * Open source code, released under the BSD license. Please improve this code | 
        
        
           | 
            for clarity, bug-fixes and feature improvements, but only to improve | 
        
        
           | 
            efficiency where it is not at the expense of a reader's easy comprehension of | 
        
        
           | 
            the algorithms and binary representation. | 
        
        
           | 
          
 | 
        
        
           | 
          * Can represent any (sign, characteristic, significand) IEEE 754-style format, | 
        
        
           | 
            and is not restricted to representations with total precision less than 64 | 
        
        
           | 
            bits. The internal representations and arithmetic are done using arbitrary | 
        
        
           | 
            precision and do not depend on the python 'float' (64 bit) class. | 
        
        
           | 
          
 | 
        
        
           | 
          * Rounding modes offered are 'up', 'down', 'floor', 'ceiling', 'half_up', | 
        
        
           | 
            and 'half_down'. | 
        
        
           | 
          
 | 
        
        
           | 
          * Arithmetic operations are only permitted between numbers represented in | 
        
        
           | 
            exactly the same format. | 
        
        
           | 
          
 | 
        
        
           | 
          * A binary integer class is also implemented with its associated integer | 
        
        
           | 
            arithmetic and shift operations (no logical operations). | 
        
        
           | 
          
 | 
        
        
           | 
          * max, min, sqrt, power functions are defined for the appropriate numeric | 
        
        
           | 
            classes. | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          See the following for details, and references therein: | 
        
        
           | 
          http://en.wikipedia.org/wiki/Floating_point | 
        
        
           | 
          http://en.wikipedia.org/wiki/Rounding | 
        
        
           | 
          http://en.wikipedia.org/wiki/IEEE_754 | 
        
        
           | 
          http://en.wikipedia.org/wiki/Binary_numeral_system | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ***** Known issues | 
        
        
           | 
          
 | 
        
        
           | 
          * Binary floating point arithmetic not simulated in its native form, but through | 
        
        
           | 
            internal use of arbitrary precision Decimal floating point numbers. It would | 
        
        
           | 
            be preferable to have a pure binary arithmetic implementation that | 
        
        
           | 
            demonstrates shifting of exponents, etc. before addition. | 
        
        
           | 
          
 | 
        
        
           | 
          * Does not directly simulate the algorithmic implementations by which | 
        
        
           | 
            IEEE 754 arithmetic and rounding is performed in CPUs. e.g. rounding up | 
        
        
           | 
            is *not* achieved by adding 0.5 and then truncating in this code. | 
        
        
           | 
          
 | 
        
        
           | 
          * Creation of higher precision floats is slow due to python implementation of | 
        
        
           | 
            frexp function. | 
        
        
           | 
          
 | 
        
        
           | 
          * Boolean operations on binary floating point numbers are not supported at this | 
        
        
           | 
            time. | 
        
        
           | 
          
 | 
        
        
           | 
          * Please note that float(Decimal("Inf")) will not work in Python 2.5 due to a | 
        
        
           | 
            problem in Python itself. This has been fixed in Python 2.6 and above | 
        
        
           | 
            (http://bugs.python.org/issue3188). | 
        
        
           | 
          
 | 
        
        
           | 
          * ContextClass does not support initialization from numpy float128 values. Needs | 
        
        
           | 
            additional code to extract byte-by-byte hex representation from the 'data' | 
        
        
           | 
            attribute of such a value, and conversion into equivalent binary string. | 
        
        
           | 
          
 | 
        
        
           | 
          * eval(repr(x)) when x is a ContextClass instance creates a Binary object with | 
        
        
           | 
            the same representation (fixed precision, rounding) as x, not another | 
        
        
           | 
            ContextClass instance. However, x == eval(repr(x)). | 
        
        
           | 
          
 | 
        
        
           | 
          * decimal context precision value must not be changed by the user to be less | 
        
        
           | 
            than the precision required by any ContextClass instances (Binary numbers of a | 
        
        
           | 
            fixed precision), otherwise arithmetic on those numbers may be inaccurate. | 
        
        
           | 
            In Python 2.5 and above, local context could be established for these | 
        
        
           | 
            calculations using the with statement (see here for implementation details: | 
        
        
           | 
            http://docs.python.org/lib/decimal-decimal.html). See binary_py25.py. | 
        
        
           | 
          
 | 
        
        
           | 
          * mod, floordiv, divmod methods are not supported. | 
        
        
           | 
          
 | 
        
        
           | 
          * Can be slow to evaluate expressions involving high precision values. | 
        
        
           | 
          
 | 
        
        
           | 
          * Can hash a binary context (ContextClass instance), but cannot hash | 
        
        
           | 
            a decimal.context instance. | 
        
        
           | 
          
 | 
        
        
           | 
          * Requires numpy to be installed, in order to use numpy.sign, numpy.zeros | 
        
        
           | 
            and provide compatibility with numpy.float32, numpy.float64, and | 
        
        
           | 
            numpy.float128 values. The sign function and array use provide better speed | 
        
        
           | 
            in key parts of the algorithms, but could be easily replaced to make | 
        
        
           | 
            numpy installation optional. | 
        
        
           | 
          
 | 
        
        
           | 
          * Does not support use of minifloats (IEEE-754 style formats with very low | 
        
        
           | 
            bit lengths for the exponent and characteristic) for integer-only | 
        
        
           | 
            representations. (This is a common application of such values, according to | 
        
        
           | 
            http://en.wikipedia.org/wiki/Minifloat.) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ***** Usage | 
        
        
           | 
          
 | 
        
        
           | 
          ** Constructors: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> context = define_context(5, 12, ROUND_DOWN) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          Equivalent binary float values in a given context: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x = Binary('-0.1111', context)          # binary fraction assumed by default | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x = Binary(Decimal("-0.9375"), context) # decimal fraction | 
        
        
           | 
          
 | 
        
        
           | 
          The following represent the same binary number (in context) but are a way | 
        
        
           | 
          to directly specify the representation in terms of the underlying context | 
        
        
           | 
          
 | 
        
        
           | 
          >>> a = context('1 01110 111000000000')   # (sign, characteristic, significand) | 
        
        
           | 
          
 | 
        
        
           | 
          >>> a = context('101110111000000000')     # (sign, characteristic, significand) | 
        
        
           | 
          
 | 
        
        
           | 
          These alternative forms are also valid, for convenience: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> a = context(Decimal("-0.9375")) | 
        
        
           | 
          
 | 
        
        
           | 
          >>> a = context(Binary('-0.1111')) | 
        
        
           | 
          
 | 
        
        
           | 
          If the python float literal -0.9375 is exactly representable in the context, | 
        
        
           | 
          then this is also equivalent: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> a = context(-0.9375) | 
        
        
           | 
          
 | 
        
        
           | 
          >>> a = context(numpy.float64(-0.9375)) | 
        
        
           | 
          
 | 
        
        
           | 
          Otherwise, the resulting representation in a will be to the "nearest" | 
        
        
           | 
          representable value under the rules of the context's precision and rounding | 
        
        
           | 
          mode. | 
        
        
           | 
          
 | 
        
        
           | 
          The values in a are instances of the context, and are not Binary class | 
        
        
           | 
          instances. | 
        
        
           | 
          
 | 
        
        
           | 
          Note that a context instance cannot be initialized directly using a string | 
        
        
           | 
          literal for a binary fraction, to avoid ambiguity with the primary use | 
        
        
           | 
          case, namely with input strings for (sign, characteristic, significand). | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          The Binary constructor can also represent *arbitrary* precision binary values in | 
        
        
           | 
          the absence of a given context. After any of the above definitions of x: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x.context | 
        
        
           | 
          <class 'binary.Float_5_12_D'> | 
        
        
           | 
          
 | 
        
        
           | 
          However: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> y = Binary('0.110100101010101011110001111100001e5') | 
        
        
           | 
          
 | 
        
        
           | 
          >>> y.context is None | 
        
        
           | 
          True | 
        
        
           | 
          
 | 
        
        
           | 
          Note that infinite binary precision is not possible to specify from a | 
        
        
           | 
          Decimal object, in case the binary representation is non-terminating. | 
        
        
           | 
          
 | 
        
        
           | 
          >>> b = Binary(Decimal("0.1")) | 
        
        
           | 
          ValueError: Cannot create arbitrary precision binary value without a | 
        
        
           | 
             representation context | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ** Views: | 
        
        
           | 
          
 | 
        
        
           | 
          For a context instance x (not a Binary instance), we slightly break the | 
        
        
           | 
          tradition that eval(repr(x)) is identically the same type as x. However, | 
        
        
           | 
          eval(repr(x)) == x and the evaluation leads to a Binary object with the same | 
        
        
           | 
          context. | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x = context(Decimal("-0.9375")) | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x                 # default 'view' is as binary | 
        
        
           | 
          Binary("-0.1111E0", (5, 12, ROUND_DOWN)) | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bx = eval(repr(x)) | 
        
        
           | 
          >>> bx == x | 
        
        
           | 
          True | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bx.context | 
        
        
           | 
          <class 'binary.Float_5_12_D'> | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bx.context == x.context   # bx really quacks like a duck | 
        
        
           | 
          True | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x.as_binary()     # output always in scientific notation with 0 before radix | 
        
        
           | 
          Binary("-0.1111E0") | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x.as_binary() == bx  # x.as_binary() keeps the same context | 
        
        
           | 
          True | 
        
        
           | 
          
 | 
        
        
           | 
          >>> x.as_decimal() | 
        
        
           | 
          Decimal("-0.9375") | 
        
        
           | 
          
 | 
        
        
           | 
          >>> print x | 
        
        
           | 
          1 01110 111000000000 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ** Comparisons: | 
        
        
           | 
          
 | 
        
        
           | 
          Can only compare like representations from a given context. | 
        
        
           | 
          
 | 
        
        
           | 
          >>> d = double(1) | 
        
        
           | 
          >>> q = quadruple(1) | 
        
        
           | 
          >>> d == q | 
        
        
           | 
          ValueError: Mismatched precision | 
        
        
           | 
          
 | 
        
        
           | 
          If you want to compare the actual values that these objects represent, convert | 
        
        
           | 
          them to a Binary number first | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bd = Binary(double(1)) | 
        
        
           | 
          >>> bq = Binary(quadruple(1)) | 
        
        
           | 
          >>> bd == bq | 
        
        
           | 
          True | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bd == 1.0   # cannot compare with python-native floats | 
        
        
           | 
          TypeError: Invalid object for comparison | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bd > 1 | 
        
        
           | 
          False | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bd == Decimal("1") | 
        
        
           | 
          True | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ** Conversions: | 
        
        
           | 
          
 | 
        
        
           | 
          For high precision floats with long mantissas, convert them accurately to | 
        
        
           | 
          Decimal type. Note that Decimal(str(f)) will not be accurate for floats f | 
        
        
           | 
          with mantissas longer than the displayable length of f by the str function. | 
        
        
           | 
          Thus float(Decimal(str(f))) != f for some f. To avoid this, create the | 
        
        
           | 
          representation of the float in the appropriate context by | 
        
        
           | 
          
 | 
        
        
           | 
          double(f) | 
        
        
           | 
          
 | 
        
        
           | 
          which will be a precise representation of f in double precision, where f | 
        
        
           | 
          can be a python float, numpy.float64. For numpy.float32 use single(f). | 
        
        
           | 
          
 | 
        
        
           | 
          Binary values in one context can be converted (coerced) to another thus: | 
        
        
           | 
          
 | 
        
        
           | 
          >>> xs = Binary('-1111.001', single) | 
        
        
           | 
          >>> xd = Binary(xs, double) | 
        
        
           | 
          
 | 
        
        
           | 
          or | 
        
        
           | 
          
 | 
        
        
           | 
          >>> xd = Binary(double(xs)) | 
        
        
           | 
          
 | 
        
        
           | 
          ** Arithmetic: | 
        
        
           | 
          
 | 
        
        
           | 
          Can only perform arithmetic on representations from a given context with | 
        
        
           | 
          other instances of the same context (including Binary instances with | 
        
        
           | 
          identical context). | 
        
        
           | 
          
 | 
        
        
           | 
          To perform arbitray precision arithmetic with mixed representations, | 
        
        
           | 
          first convert to Binary type, which does not care about the precision of | 
        
        
           | 
          the operands: the operation returns a new Binary value of the precise | 
        
        
           | 
          result, without context if neither operand had context, otherwise with | 
        
        
           | 
          the highest precision context. In a tie, arithmetic is not possible unless | 
        
        
           | 
          the rounding is the same. | 
        
        
           | 
          
 | 
        
        
           | 
          >>> bd = Binary(double(1.5)) | 
        
        
           | 
          >>> bq = Binary(quadruple(0.1)) | 
        
        
           | 
          >>> c = bd + bq | 
        
        
           | 
          >>> print c | 
        
        
           | 
          0.11001100110011001100110011001100110011001100110011001101E1 | 
        
        
           | 
          
 | 
        
        
           | 
          >>> c.__class__ | 
        
        
           | 
          <class 'binary.Binary'> | 
        
        
           | 
          
 | 
        
        
           | 
          >>> c.context   # coerced to the higher precision | 
        
        
           | 
          <class 'binary.Float_15_112_HU'> | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          Also see test_simfloat.py for many more examples and validations. | 
        
        
           | 
          
 | 
        
        
           | 
          """ | 
        
        
           | 
          
 | 
        
        
           | 
          import numpy as npy | 
        
        
           | 
          import math | 
        
        
           | 
          import decimal | 
        
        
           | 
          from decimal import Decimal | 
        
        
           | 
          
 | 
        
        
           | 
          __all__ = ['Decimal', 'Binary', 'ContextClass', 'BinaryIntClass', | 
        
        
           | 
                     'quadruple', 'double', 'define_context', 'frexp', 'dec_context', | 
        
        
           | 
                     'single', 'half', 'test', 'binstr2dec', 'decfrac2binrep', | 
        
        
           | 
                     'decint2binstr', 'binfracstr2decfrac', 'dec2binstr', 'binvalstr2dec', | 
        
        
           | 
                     'ROUND_UP', 'ROUND_DOWN', 'ROUND_CEILING', 'ROUND_FLOOR', | 
        
        
           | 
                     'ROUND_HALF_UP', 'ROUND_HALF_DOWN', | 
        
        
           | 
                     'BinaryOverflow', 'BinaryUnderflow', 'BinaryOverflow', | 
        
        
           | 
                     'BinaryNegativeValue', 'BinaryRemainderValue', 'BinaryException'] | 
        
        
           | 
          
 | 
        
        
           | 
          # Rounding | 
        
        
           | 
          # up = always away from 0 | 
        
        
           | 
          ROUND_UP = 'ROUND_UP' | 
        
        
           | 
          # down = always towards 0 (truncate) | 
        
        
           | 
          ROUND_DOWN = 'ROUND_DOWN' | 
        
        
           | 
          # ceiling = always towards +inf | 
        
        
           | 
          ROUND_CEILING = 'ROUND_CEILING' | 
        
        
           | 
          # floor = always towards -inf | 
        
        
           | 
          ROUND_FLOOR = 'ROUND_FLOOR' | 
        
        
           | 
          # half up = to nearest, 0.1b (0.5d) rounds away from 0 (standard and default) | 
        
        
           | 
          ROUND_HALF_UP = 'ROUND_HALF_UP' | 
        
        
           | 
          # half down = to nearest, 0.1 (0.5d) rounds towards 0 | 
        
        
           | 
          ROUND_HALF_DOWN = 'ROUND_HALF_DOWN' | 
        
        
           | 
          
 | 
        
        
           | 
          _round_code = {ROUND_UP: 'U', ROUND_DOWN: 'D', ROUND_CEILING: 'C', | 
        
        
           | 
                         ROUND_FLOOR: 'F', ROUND_HALF_UP: 'HU', ROUND_HALF_DOWN: 'HD'} | 
        
        
           | 
          
 | 
        
        
           | 
          dec_context = decimal.getcontext() | 
        
        
           | 
          dec_context.prec = 128 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryIntClass(object): | 
        
        
           | 
              """Abstract class for non-negative binary integer values only, with a fixed | 
        
        
           | 
              number of digits given by class attribute 'digits'. Set digits in a concrete | 
        
        
           | 
              subclass. The initialization value string will cause an exception if the | 
        
        
           | 
              binary value is longer than the class' digits setting. | 
        
        
           | 
              """ | 
        
        
           | 
              digits = None | 
        
        
           | 
          
 | 
        
        
           | 
              def __init__(self, value): | 
        
        
           | 
                  """Initialize with a value made up of a string of binary digits. | 
        
        
           | 
                  """ | 
        
        
           | 
                  dec_value = int(value, base=2) | 
        
        
           | 
                  if dec_value < 0: | 
        
        
           | 
                      raise BinaryNegativeValue("Invalid binary value: out of range of %d-digit number"%self.digits) | 
        
        
           | 
                  elif dec_value > self.largest: | 
        
        
           | 
                      raise BinaryOverflow("Invalid binary value: out of range of %d-digit number"%self.digits) | 
        
        
           | 
                  self.bin_value = pad(value, self.digits) | 
        
        
           | 
                  self.dec_value = Decimal(dec_value) | 
        
        
           | 
                  self.tuple_rep = tuple([int(bit) for bit in self.bin_value]) | 
        
        
           | 
          
 | 
        
        
           | 
              def __repr__(self): | 
        
        
           | 
                  return '%s("%s")' % (self.__class__.__name__, self.bin_value) | 
        
        
           | 
          
 | 
        
        
           | 
              def __str__(self): | 
        
        
           | 
                  return self.bin_value | 
        
        
           | 
          
 | 
        
        
           | 
              def as_decimal(self): | 
        
        
           | 
                  return self.dec_value | 
        
        
           | 
          
 | 
        
        
           | 
              def as_binary(self): | 
        
        
           | 
                  return 'Binary("%s")' % self.bin_value | 
        
        
           | 
          
 | 
        
        
           | 
              def as_tuple(self): | 
        
        
           | 
                  return self.tuple_rep | 
        
        
           | 
          
 | 
        
        
           | 
              def _op_return_class(self, other): | 
        
        
           | 
                  try: | 
        
        
           | 
                      other_digits = other.digits | 
        
        
           | 
                  except AttributeError: | 
        
        
           | 
                      raise TypeError("Invalid Binary object") | 
        
        
           | 
                  if other_digits > self.digits: | 
        
        
           | 
                      new_class = other.__class__ | 
        
        
           | 
                  else: | 
        
        
           | 
                      new_class = self.__class__ | 
        
        
           | 
                  return new_class | 
        
        
           | 
          
 | 
        
        
           | 
              def max(self, other): | 
        
        
           | 
                  return self.dec_value.max(other) | 
        
        
           | 
          
 | 
        
        
           | 
              def min(self, other): | 
        
        
           | 
                  return self.dec_value.min(other) | 
        
        
           | 
          
 | 
        
        
           | 
              def __add__(self, other): | 
        
        
           | 
                  new_class = self._op_return_class(other) | 
        
        
           | 
                  result = self.dec_value + other.dec_value | 
        
        
           | 
                  try: | 
        
        
           | 
                      return new_class(decint2binstr(result)) | 
        
        
           | 
                  except ValueError: | 
        
        
           | 
                      raise BinaryOverflow(result) | 
        
        
           | 
          
 | 
        
        
           | 
              def __sub__(self, other): | 
        
        
           | 
                  new_class = self._op_return_class(other) | 
        
        
           | 
                  result = self.dec_value - other.dec_value | 
        
        
           | 
                  if result < 0: | 
        
        
           | 
                      raise BinaryNegativeValue(result) | 
        
        
           | 
                  return new_class(decint2binstr(result)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __mul__(self, other): | 
        
        
           | 
                  new_class = self._op_return_class(other) | 
        
        
           | 
                  result = self.dec_value * other.dec_value | 
        
        
           | 
                  try: | 
        
        
           | 
                      return new_class(decint2binstr(result)) | 
        
        
           | 
                  except ValueError: | 
        
        
           | 
                      raise BinaryOverflow(result) | 
        
        
           | 
          
 | 
        
        
           | 
              def __div__(self, other): | 
        
        
           | 
                  new_class = self._op_return_class(other) | 
        
        
           | 
                  result_dm = divmod(self.dec_value, other.dec_value) | 
        
        
           | 
                  if result_dm[1] != 0: | 
        
        
           | 
                      raise BinaryRemainderValue(result_dm) | 
        
        
           | 
                  return new_class(decint2binstr(result_dm[0])) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rshift__(self, y): | 
        
        
           | 
                  result = self.dec_value >> y | 
        
        
           | 
                  return self.__class__(decint2binstr(result)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __lshift__(self, y): | 
        
        
           | 
                  result = self.dec_value << y | 
        
        
           | 
                  try: | 
        
        
           | 
                      return self.__class__(decint2binstr(result)) | 
        
        
           | 
                  except ValueError: | 
        
        
           | 
                      raise BinaryOverflow(result) | 
        
        
           | 
          
 | 
        
        
           | 
              def __hash__(self): | 
        
        
           | 
                  """Hash as per the precise decimal representation. | 
        
        
           | 
                  """ | 
        
        
           | 
                  return hash(self.dec_value) | 
        
        
           | 
          
 | 
        
        
           | 
              def next(self): | 
        
        
           | 
                  try: | 
        
        
           | 
                      return self.__class__(decint2binstr(int(self.bin_value, | 
        
        
           | 
                                                          base=2) + 1)) | 
        
        
           | 
                  except BinaryOverflow: | 
        
        
           | 
                      raise BinaryOverflow(int(self.bin_value, base=2) + 1) | 
        
        
           | 
          
 | 
        
        
           | 
              def prev(self): | 
        
        
           | 
                  try: | 
        
        
           | 
                      return self.__class__(decint2binstr(int(self.bin_value, | 
        
        
           | 
                                                              base=2) - 1)) | 
        
        
           | 
                  except: | 
        
        
           | 
                      raise BinaryNegativeValue(int(self.bin_value, base=2) - 1) | 
        
        
           | 
          
 | 
        
        
           | 
              def __hash__(self): | 
        
        
           | 
                  return hash(repr(self)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __getitem__(self, i): | 
        
        
           | 
                  return int(self.bin_value[i]) | 
        
        
           | 
          
 | 
        
        
           | 
              ## could provide boolean operator methods but not needed for arithmetic | 
        
        
           | 
          
 | 
        
        
           | 
              def __reduce__(self): | 
        
        
           | 
                  return (self.__class__, (repr(self),)) | 
        
        
           | 
          
 | 
        
        
           | 
          class SignBit(BinaryIntClass): | 
        
        
           | 
              digits = 1 | 
        
        
           | 
              largest = 1 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryCharacteristic(BinaryIntClass): | 
        
        
           | 
              """Abstract class for floating point representation's characteristic, | 
        
        
           | 
              a.k.a. exponent. | 
        
        
           | 
              """ | 
        
        
           | 
              def __init__(self, value): | 
        
        
           | 
                  """value is a binary string representatino of the exponent (so may be | 
        
        
           | 
                  negative)""" | 
        
        
           | 
                  BinaryIntClass.__init__(self, value) | 
        
        
           | 
                  # interpretation-related attributes | 
        
        
           | 
                  interp_dec_value = self.dec_value - self.bias | 
        
        
           | 
                  if interp_dec_value < self.exp_lowest: | 
        
        
           | 
                      raise BinaryNegativeValue("Invalid binary value: out of range of %d-digit number"%self.digits) | 
        
        
           | 
                  if interp_dec_value > self.exp_largest: | 
        
        
           | 
                      raise BinaryOverflow("Invalid binary value: out of range of %d-digit number"%self.digits) | 
        
        
           | 
                  self.interp_dec_value = interp_dec_value | 
        
        
           | 
          
 | 
        
        
           | 
              def interpret(self, denorm=False): | 
        
        
           | 
                  """Interpret raw binary value as a signed decimal integer. | 
        
        
           | 
                  """ | 
        
        
           | 
                  if denorm: | 
        
        
           | 
                      # bias needs to be adjusted by 1 | 
        
        
           | 
                      return self.interp_dec_value + 1 | 
        
        
           | 
                  else: | 
        
        
           | 
                      return self.interp_dec_value | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          class BinarySignificand(BinaryIntClass): | 
        
        
           | 
              """Abstract class for floating point representation's significand, | 
        
        
           | 
              a.k.a. fraction, or mantissa. | 
        
        
           | 
              """ | 
        
        
           | 
              def interpret(self): | 
        
        
           | 
                  """Interpret raw binary value as a decimal fraction. | 
        
        
           | 
                  """ | 
        
        
           | 
                  return binfracstr2decfrac(self.bin_value) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          class ContextClass(object): | 
        
        
           | 
              """Abstract class for immutable binary floating point number using | 
        
        
           | 
              (sign, characteristic, significand) representation. | 
        
        
           | 
              """ | 
        
        
           | 
              def __init__(self, value): | 
        
        
           | 
                  """Initialize with decimal value (either of type 'float' or 'Decimal') | 
        
        
           | 
                  or a binary digit string of total length = <this_class>.digits or the | 
        
        
           | 
                  same string with spaces between sign, characteristic, and significand | 
        
        
           | 
                  elements (total length <this_class>.digits+2). | 
        
        
           | 
                  """ | 
        
        
           | 
                  try: | 
        
        
           | 
                      assert self.significandClass.digits is not None | 
        
        
           | 
                  except AssertionError: | 
        
        
           | 
                      raise NotImplementedError("Create concrete sub-type of ContextClass") | 
        
        
           | 
          
 | 
        
        
           | 
                  # round_dir may be overwritten by init_from_dec | 
        
        
           | 
                  # round_dir =  None  => no rounding needed | 
        
        
           | 
                  #             'next' => use next towards +inf | 
        
        
           | 
                  #             'prev' => use next towards -inf | 
        
        
           | 
                  round_dir = None | 
        
        
           | 
          
 | 
        
        
           | 
                  if isinstance(value, (float, npy.float64)): | 
        
        
           | 
                      if not npy.isfinite(value): | 
        
        
           | 
                          val_str = str(value) | 
        
        
           | 
                          # val_str may be '1.#INF' rather than 'inf' on some platforms | 
        
        
           | 
                          val_str = val_str.replace('.', '').replace('#', '').replace('1', | 
        
        
           | 
                                                                                      '') | 
        
        
           | 
                          round_dir = self.init_from_dec(Decimal(val_str)) | 
        
        
           | 
                      else: | 
        
        
           | 
                          if value < 0: | 
        
        
           | 
                              fval = -value | 
        
        
           | 
                              s = '1' | 
        
        
           | 
                          else: | 
        
        
           | 
                              fval = value | 
        
        
           | 
                              s = '0' | 
        
        
           | 
                          # extract full binary representation of the value | 
        
        
           | 
                          # (which is not accessible from str(value) or repr(value) | 
        
        
           | 
                          valstr = pad(decint2binstr(npy.int64( \ | 
        
        
           | 
                                          npy.array(fval).view(long))), 64) | 
        
        
           | 
                          e = valstr[1:12] | 
        
        
           | 
                          f = valstr[12:] | 
        
        
           | 
                          denorm = int(e) == 0 and int(f) > 0 | 
        
        
           | 
                          if denorm: | 
        
        
           | 
                              bias = 1022 | 
        
        
           | 
                              expo = Decimal(2)**Decimal(int(e, base=2) - bias) | 
        
        
           | 
                              frac = binfracstr2decfrac(f) | 
        
        
           | 
                          else: | 
        
        
           | 
                              bias = 1023 | 
        
        
           | 
                              expo = Decimal(2)**Decimal(int(e, base=2) - bias) | 
        
        
           | 
                              frac = 1 + binfracstr2decfrac(f) | 
        
        
           | 
                          try: | 
        
        
           | 
                              round_dir = self.init_from_dec((-1)**int(s) * expo * frac) | 
        
        
           | 
                          except: | 
        
        
           | 
                              raise BinaryOverflow("Invalid representation for this class: %s"%value) | 
        
        
           | 
          
 | 
        
        
           | 
                  elif isinstance(value, npy.float32): | 
        
        
           | 
                      if not npy.isfinite(value): | 
        
        
           | 
                          val_str = str(value) | 
        
        
           | 
                          # val_str may be '1.#INF' rather than 'inf' on some platforms | 
        
        
           | 
                          val_str = val_str.replace('.', '').replace('#', '').replace('1', | 
        
        
           | 
                                                                                      '') | 
        
        
           | 
                          round_dir = self.init_from_dec(Decimal(val_str)) | 
        
        
           | 
                      else: | 
        
        
           | 
                          if value < 0: | 
        
        
           | 
                              fval = -value | 
        
        
           | 
                              s = '1' | 
        
        
           | 
                          else: | 
        
        
           | 
                              fval = value | 
        
        
           | 
                              s = '0' | 
        
        
           | 
                          # extract full binary representation of the value | 
        
        
           | 
                          # (which is not accessible from str(value) or repr(value) | 
        
        
           | 
                          valstr = pad(decint2binstr(npy.int32( \ | 
        
        
           | 
                                        npy.array(fval).view(int))), 32) | 
        
        
           | 
                          e = valstr[1:9] | 
        
        
           | 
                          f = valstr[9:] | 
        
        
           | 
          
 | 
        
        
           | 
                          denorm = int(e) == 0 and int(f) > 0 | 
        
        
           | 
                          if denorm: | 
        
        
           | 
                              bias = 126 | 
        
        
           | 
                              expo = Decimal(2) ** Decimal(int(e, base=2) - bias) | 
        
        
           | 
                              frac = binfracstr2decfrac(f) | 
        
        
           | 
                          else: | 
        
        
           | 
                              bias = 127 | 
        
        
           | 
                              expo = Decimal(2) ** Decimal(int(e, base=2) - bias) | 
        
        
           | 
                              frac = 1 + binfracstr2decfrac(f) | 
        
        
           | 
                          try: | 
        
        
           | 
                              round_dir = self.init_from_dec((-1)**int(s) * expo * frac) | 
        
        
           | 
                          except: | 
        
        
           | 
                              raise BinaryOverflow("Invalid representation for this class: %s"%value) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
                  elif isinstance(value, (int, long, npy.int64, npy.int32)): | 
        
        
           | 
                      try: | 
        
        
           | 
                          round_dir = self.init_from_dec(Decimal(value)) | 
        
        
           | 
                      except OverflowError: | 
        
        
           | 
                          raise BinaryOverflow() | 
        
        
           | 
          
 | 
        
        
           | 
                  elif isinstance(value, Decimal): | 
        
        
           | 
                      try: | 
        
        
           | 
                          round_dir = self.init_from_dec(value) | 
        
        
           | 
                      except OverflowError: | 
        
        
           | 
                          raise BinaryOverflow() | 
        
        
           | 
          
 | 
        
        
           | 
                  elif isinstance(value, Binary): | 
        
        
           | 
                      try: | 
        
        
           | 
                          round_dir = self.init_from_dec(value.dec) | 
        
        
           | 
                      except OverflowError: | 
        
        
           | 
                          raise BinaryOverflow() | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
                  elif isinstance(value, str): | 
        
        
           | 
                      if len(value) == self.digits: | 
        
        
           | 
                          # e.g. "11101001111010000" | 
        
        
           | 
                          s = value[0] | 
        
        
           | 
                          e = value[1:self.characteristicClass.digits+1] | 
        
        
           | 
                          f = value[self.characteristicClass.digits+1:] | 
        
        
           | 
                      elif len(value) == self.digits + 2: | 
        
        
           | 
                          # e.g. "1 1101 001111010000" | 
        
        
           | 
                          try: | 
        
        
           | 
                              s, e, f = value.split(' ') | 
        
        
           | 
                          except: | 
        
        
           | 
                              raise ValueError("Invalid string representation for this class: %s"%value) | 
        
        
           | 
                      else: | 
        
        
           | 
                          raise ValueError("Invalid string representation for this class: %s"%value) | 
        
        
           | 
                      try: | 
        
        
           | 
                          self.init_from_string(s, e, f) | 
        
        
           | 
                      except: | 
        
        
           | 
                          raise ValueError("Invalid string representation for this class: %s"%value) | 
        
        
           | 
          
 | 
        
        
           | 
                  else: | 
        
        
           | 
                      raise TypeError("Invalid initialization type") | 
        
        
           | 
          
 | 
        
        
           | 
                  self.tuple_rep = tuple((self.signbit.as_tuple(), | 
        
        
           | 
                                          self.characteristic.as_tuple(), | 
        
        
           | 
                                          self.significand.as_tuple())) | 
        
        
           | 
          
 | 
        
        
           | 
                  # treat special cases for 0, Inf, NaN, and denormalized values | 
        
        
           | 
                  if self.characteristic.dec_value == 0: | 
        
        
           | 
                      if self.significand.dec_value == 0: | 
        
        
           | 
                          # zeros | 
        
        
           | 
                          if self.signbit.dec_value == 0: | 
        
        
           | 
                              self.dec_value = Decimal("0") | 
        
        
           | 
                              self.bin_value = "0" | 
        
        
           | 
                          else: | 
        
        
           | 
                              self.dec_value = Decimal("-0") | 
        
        
           | 
                              self.bin_value = "-0" | 
        
        
           | 
                      else: | 
        
        
           | 
                          # denormalized values | 
        
        
           | 
                          self.dec_value = (-1)**self.signbit.dec_value * \ | 
        
        
           | 
                                2**(self.characteristic.interpret(denorm=True)) * \ | 
        
        
           | 
                               (0 + self.significand.interpret()) | 
        
        
           | 
                          # lazy determination of bin_value when it is requested | 
        
        
           | 
                          # (slow calculation) | 
        
        
           | 
                          self.bin_value = "" | 
        
        
           | 
                  elif self.characteristic.dec_value == self.characteristic.largest: | 
        
        
           | 
                      if self.significand.dec_value == 0: | 
        
        
           | 
                          # +/- Inf | 
        
        
           | 
                          if self.signbit.dec_value == 0: | 
        
        
           | 
                              self.dec_value = Decimal("Inf") | 
        
        
           | 
                              self.bin_value = "Inf" | 
        
        
           | 
                          else: | 
        
        
           | 
                              self.dec_value = Decimal("-Inf") | 
        
        
           | 
                              self.bin_value = "-Inf" | 
        
        
           | 
                      else: | 
        
        
           | 
                          # NaN | 
        
        
           | 
                          self.dec_value = Decimal("NaN") | 
        
        
           | 
                          self.bin_value = "NaN" | 
        
        
           | 
                  else: | 
        
        
           | 
                      # normalized values | 
        
        
           | 
                      self.dec_value = (-1)**self.signbit.dec_value * \ | 
        
        
           | 
                                  2**(self.characteristic.interpret()) * \ | 
        
        
           | 
                                  (1 + self.significand.interpret()) | 
        
        
           | 
                      # lazy determination of bin_value when it is requested | 
        
        
           | 
                      # (slow calculation) | 
        
        
           | 
                      self.bin_value = "" | 
        
        
           | 
          
 | 
        
        
           | 
                  if round_dir is not None: | 
        
        
           | 
                      new = getattr(self, round_dir)() | 
        
        
           | 
                      self.signbit = new.signbit | 
        
        
           | 
                      self.characteristic = new.characteristic | 
        
        
           | 
                      self.significand = new.significand | 
        
        
           | 
                      self.bin_value = new.bin_value | 
        
        
           | 
                      self.dec_value = new.dec_value | 
        
        
           | 
                      self.tuple_rep = new.tuple_rep | 
        
        
           | 
          
 | 
        
        
           | 
                  # for compatibility with Binary attribute | 
        
        
           | 
                  self.context = self.__class__ | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
              def init_from_string(self, s, char_str, mant_str): | 
        
        
           | 
                  self.signbit = SignBit(s) | 
        
        
           | 
                  self.characteristic = self.characteristicClass(char_str) | 
        
        
           | 
                  self.significand = self.significandClass(mant_str) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
              def init_from_dec(self, d): | 
        
        
           | 
                  """d is a Decimal object""" | 
        
        
           | 
                  if d._isnan(): | 
        
        
           | 
                      self.signbit = SignBit('0') | 
        
        
           | 
                      self.characteristic = \ | 
        
        
           | 
                          self.characteristicClass("1"*self.characteristicClass.digits) | 
        
        
           | 
                      self.significand = \ | 
        
        
           | 
                          self.significandClass("1"*self.significandClass.digits) | 
        
        
           | 
                      return None | 
        
        
           | 
                  elif d._isinfinity() != 0: | 
        
        
           | 
                      self.signbit = SignBit(str(bin_sign(d._isinfinity()))) | 
        
        
           | 
                      self.characteristic = \ | 
        
        
           | 
                          self.characteristicClass("1"*self.characteristicClass.digits) | 
        
        
           | 
                      self.significand = \ | 
        
        
           | 
                          self.significandClass("0"*self.significandClass.digits) | 
        
        
           | 
                      return None | 
        
        
           | 
                  if d < 0: | 
        
        
           | 
                      s = '1' | 
        
        
           | 
                      d = -d | 
        
        
           | 
                  elif d == 0: | 
        
        
           | 
                      self.signbit = SignBit('0') | 
        
        
           | 
                      self.characteristic = \ | 
        
        
           | 
                          self.characteristicClass("0"*self.characteristicClass.digits) | 
        
        
           | 
                      self.significand = \ | 
        
        
           | 
                          self.significandClass("0"*self.significandClass.digits) | 
        
        
           | 
                      # no rounding, so return None | 
        
        
           | 
                      return None | 
        
        
           | 
                  else: | 
        
        
           | 
                      s = '0' | 
        
        
           | 
                  if d <= self.largest_denorm: | 
        
        
           | 
                      bias = self.characteristicClass.bias-1 | 
        
        
           | 
                      frac_leading = 0 | 
        
        
           | 
                  else: | 
        
        
           | 
                      bias = self.characteristicClass.bias | 
        
        
           | 
                      frac_leading = 1 | 
        
        
           | 
          
 | 
        
        
           | 
                  # acquire precise fraction, exponent (given that exponent must be | 
        
        
           | 
                  # representable in this class) | 
        
        
           | 
                  f_dec, e_dec = frexp(d, self) | 
        
        
           | 
                  e_dec += bias | 
        
        
           | 
          
 | 
        
        
           | 
                  # convert to binary and round to precision of significand | 
        
        
           | 
                  i = 0 | 
        
        
           | 
                  max_bits = self.characteristicClass.exp_largest + \ | 
        
        
           | 
                             self.significandClass.digits + 2 | 
        
        
           | 
                  bfrac = npy.zeros(max_bits, int) | 
        
        
           | 
                  i_stop = max_bits | 
        
        
           | 
                  not_seen_one = True | 
        
        
           | 
                  # make sure we use extra precision (given that might adjust for | 
        
        
           | 
                  # leading 0's) | 
        
        
           | 
                  while f_dec > 0 and i < max_bits: | 
        
        
           | 
                      f_dec *= 2 | 
        
        
           | 
                      bit = int(f_dec) | 
        
        
           | 
                      if not_seen_one and bit == 1: | 
        
        
           | 
                          # first time seen a 1 know that we only need up to | 
        
        
           | 
                          # significand's more digits + 2 (speed optimization) | 
        
        
           | 
                          i_stop = i + self.significandClass.digits + 2 | 
        
        
           | 
                          not_seen_one = False | 
        
        
           | 
                      bfrac[i] = bit | 
        
        
           | 
                      f_dec -= bit | 
        
        
           | 
                      i += 1 | 
        
        
           | 
                      if i >= i_stop: | 
        
        
           | 
                          break | 
        
        
           | 
                  # binary string representation of fraction to full precision | 
        
        
           | 
                  f = ''.join([str(b) for b in bfrac[:i]]) | 
        
        
           | 
                  if frac_leading == 1: | 
        
        
           | 
                      try: | 
        
        
           | 
                          one_pos = f.index('1') | 
        
        
           | 
                      except ValueError: | 
        
        
           | 
                          # f is all 0's | 
        
        
           | 
                          pass | 
        
        
           | 
                      else: | 
        
        
           | 
                          # adjust for leading zeros | 
        
        
           | 
                          f = f[one_pos+1:] | 
        
        
           | 
                          e_dec -= one_pos+1 | 
        
        
           | 
                      c = decint2binstr(e_dec) | 
        
        
           | 
                  else: | 
        
        
           | 
                      # denormalized, inevitable lost precision in f | 
        
        
           | 
                      c = '0'*self.characteristicClass.digits | 
        
        
           | 
                      f = '0'*abs(e_dec) + f | 
        
        
           | 
                  #print(len(f), f) | 
        
        
           | 
                  #print(2**Decimal(e_dec - bias) * (frac_leading + binfracstr2decfrac(f))) | 
        
        
           | 
          
 | 
        
        
           | 
                  round_dir = None   # default | 
        
        
           | 
                  if len(c) < self.characteristicClass.digits: | 
        
        
           | 
                      c = pad(c, self.characteristicClass.digits) | 
        
        
           | 
                  if len(f) < self.significandClass.digits: | 
        
        
           | 
                      f = pad(f, self.significandClass.digits, to_right=True) | 
        
        
           | 
                  elif len(f) > self.significandClass.digits: | 
        
        
           | 
                      next_bit = int(f[self.significandClass.digits]) | 
        
        
           | 
                      try: | 
        
        
           | 
                          remaining_bits = f[self.significandClass.digits+1:] | 
        
        
           | 
                      except IndexError: | 
        
        
           | 
                          remaining_bits = '0' | 
        
        
           | 
                      else: | 
        
        
           | 
                          if remaining_bits == '': | 
        
        
           | 
                              remaining_bits = '0' | 
        
        
           | 
                      round_dir = self._round(int(s), next_bit, int(remaining_bits) > 0) | 
        
        
           | 
                      f = f[:self.significandClass.digits] | 
        
        
           | 
          
 | 
        
        
           | 
                  self.signbit = SignBit(s) | 
        
        
           | 
                  self.characteristic = self.characteristicClass(c) | 
        
        
           | 
                  self.significand = self.significandClass(f) | 
        
        
           | 
                  return round_dir | 
        
        
           | 
          
 | 
        
        
           | 
              def _round(self, sign, next_bit, non_zero_remainder): | 
        
        
           | 
                  r = self.round_mode | 
        
        
           | 
                  if r == ROUND_DOWN: | 
        
        
           | 
                      return None | 
        
        
           | 
                  elif r == ROUND_UP: | 
        
        
           | 
                      if next_bit == 1 or non_zero_remainder: | 
        
        
           | 
                          # > 0.0b in magnitude | 
        
        
           | 
                          if sign == 0: | 
        
        
           | 
                              return 'next' | 
        
        
           | 
                          else: | 
        
        
           | 
                              return 'prev' | 
        
        
           | 
                      else: | 
        
        
           | 
                          return None | 
        
        
           | 
                  elif r == ROUND_HALF_UP: | 
        
        
           | 
                      if next_bit == 1: | 
        
        
           | 
                          # >= 0.1b in magnitude, round away from 0 | 
        
        
           | 
                          if sign == 0: | 
        
        
           | 
                              return 'next' | 
        
        
           | 
                          else: | 
        
        
           | 
                              return 'prev' | 
        
        
           | 
                      else: | 
        
        
           | 
                          return None | 
        
        
           | 
                  elif r == ROUND_HALF_DOWN: | 
        
        
           | 
                      if next_bit == 1: | 
        
        
           | 
                          if non_zero_remainder: | 
        
        
           | 
                              # > 0.1b in magnitude, round away from 0 | 
        
        
           | 
                              if sign == 0: | 
        
        
           | 
                                  return 'next' | 
        
        
           | 
                              else: | 
        
        
           | 
                                  return 'prev' | 
        
        
           | 
                          else: | 
        
        
           | 
                              # = 0.1b, round towards 0 | 
        
        
           | 
                              return None | 
        
        
           | 
                      else: | 
        
        
           | 
                          return None | 
        
        
           | 
                  elif r == ROUND_CEILING: | 
        
        
           | 
                      if sign == 0: | 
        
        
           | 
                          if next_bit == 1 or non_zero_remainder: | 
        
        
           | 
                              # > 0.0b in magnitude, round towards +inf | 
        
        
           | 
                              return 'next' | 
        
        
           | 
                          else: | 
        
        
           | 
                              return None | 
        
        
           | 
                      else: | 
        
        
           | 
                          return None | 
        
        
           | 
                  elif r == ROUND_FLOOR: | 
        
        
           | 
                      if sign == 1: | 
        
        
           | 
                          if next_bit == 1 or non_zero_remainder: | 
        
        
           | 
                              # > 0.0b in magnitude, round towards +inf | 
        
        
           | 
                              return 'prev' | 
        
        
           | 
                          else: | 
        
        
           | 
                              return None | 
        
        
           | 
                      else: | 
        
        
           | 
                          return None | 
        
        
           | 
                  else: | 
        
        
           | 
                      raise ValueError("Invalid rounding type") | 
        
        
           | 
          
 | 
        
        
           | 
              def is_denormalized(self): | 
        
        
           | 
                  return self.dec_value <= self.largest_denorm | 
        
        
           | 
          
 | 
        
        
           | 
              def as_tuple(self): | 
        
        
           | 
                  return self.tuple_rep | 
        
        
           | 
          
 | 
        
        
           | 
              def as_binary(self): | 
        
        
           | 
                  """Lazy evaluation of bin_value in case it's never used. | 
        
        
           | 
                  This is done because the calculation is slow! | 
        
        
           | 
                  """ | 
        
        
           | 
                  if self.bin_value == "": | 
        
        
           | 
                      self.bin_value = dec2binstr(self.dec_value, self) | 
        
        
           | 
                  return Binary(self.bin_value, self.__class__) | 
        
        
           | 
          
 | 
        
        
           | 
              def as_decimal(self): | 
        
        
           | 
                  return self.dec_value | 
        
        
           | 
          
 | 
        
        
           | 
              def __repr__(self): | 
        
        
           | 
                  if self.bin_value == "": | 
        
        
           | 
                      self.bin_value = dec2binstr(self.dec_value, self) | 
        
        
           | 
                  return 'Binary("%s", (%s, %s, %s))' % \ | 
        
        
           | 
                                   (self.bin_value, | 
        
        
           | 
                                    self.characteristicClass.digits, | 
        
        
           | 
                                    self.significandClass.digits, | 
        
        
           | 
                                    self.round_mode) | 
        
        
           | 
          
 | 
        
        
           | 
              def __str__(self): | 
        
        
           | 
                  return "%s %s %s" % (str(self.signbit), str(self.characteristic), | 
        
        
           | 
                                       str(self.significand)) | 
        
        
           | 
          
 | 
        
        
           | 
              def next(self): | 
        
        
           | 
                  """Return the successive representable float value in the more | 
        
        
           | 
                  positive direction. | 
        
        
           | 
                  """ | 
        
        
           | 
                  if self.signbit.dec_value == 1: | 
        
        
           | 
                      method = 'prev' | 
        
        
           | 
                  else: | 
        
        
           | 
                      method = 'next' | 
        
        
           | 
                  return self._step(method) | 
        
        
           | 
          
 | 
        
        
           | 
              def prev(self): | 
        
        
           | 
                  """Return the successive representable float value in the more | 
        
        
           | 
                  negative direction. | 
        
        
           | 
                  """ | 
        
        
           | 
                  if self.signbit.dec_value == 0: | 
        
        
           | 
                      method = 'prev' | 
        
        
           | 
                  else: | 
        
        
           | 
                      method = 'next' | 
        
        
           | 
                  return self._step(method) | 
        
        
           | 
          
 | 
        
        
           | 
              def _step(self, method): | 
        
        
           | 
                  """ | 
        
        
           | 
                  Internal method for stepping to successive representable values, | 
        
        
           | 
                  either in the increasing or decreasing direction, according to the | 
        
        
           | 
                  method passed. | 
        
        
           | 
                  """ | 
        
        
           | 
                  # default value, unless switches | 
        
        
           | 
                  new_signbit = self.signbit | 
        
        
           | 
                  try: | 
        
        
           | 
                      new_signif = getattr(self.significand, method)() | 
        
        
           | 
                  except BinaryNegativeValue: | 
        
        
           | 
                      # CARRY | 
        
        
           | 
                      try: | 
        
        
           | 
                          new_char = getattr(self.characteristic, method)() | 
        
        
           | 
                      except BinaryNegativeValue: | 
        
        
           | 
                          # CHANGE SIGN | 
        
        
           | 
                          new_char = self.characteristic | 
        
        
           | 
                          new_signbit = SignBit(str(1-self.signbit.dec_value)) | 
        
        
           | 
                          # have to reset new_signif in this case | 
        
        
           | 
                          new_signif = self.significandClass(pad('1', | 
        
        
           | 
                                                                 self.significand.digits)) | 
        
        
           | 
                      except BinaryOverflow: | 
        
        
           | 
                          raise ValueError("No more representable values") | 
        
        
           | 
                      else: | 
        
        
           | 
                          new_signif = self.significandClass('1'*self.significand.digits) | 
        
        
           | 
                  except BinaryOverflow: | 
        
        
           | 
                      # CARRY | 
        
        
           | 
                      # representation of one in the same number of significant digits | 
        
        
           | 
                      new_signif = self.significandClass('0'*self.significand.digits) | 
        
        
           | 
                      try: | 
        
        
           | 
                          new_char = getattr(self.characteristic, method)() | 
        
        
           | 
                      except BinaryOverflow: | 
        
        
           | 
                          raise ValueError("No more representable values") | 
        
        
           | 
                  else: | 
        
        
           | 
                      new_char = self.characteristic | 
        
        
           | 
                  return self.__class__(" ".join([str(new_signbit), str(new_char), | 
        
        
           | 
                                                 str(new_signif)])) | 
        
        
           | 
          
 | 
        
        
           | 
              def _op_check(self, other): | 
        
        
           | 
                  try: | 
        
        
           | 
                      # may be another ContextClass with matching precision | 
        
        
           | 
                      other_sig_digits = other.significand.digits | 
        
        
           | 
                      other_char_digits = other.characteristic.digits | 
        
        
           | 
                  except AttributeError: | 
        
        
           | 
                      # may be a Binary object with matching precision | 
        
        
           | 
                      try: | 
        
        
           | 
                          other_sig_digits = other.context.significandClass.digits | 
        
        
           | 
                          other_char_digits = other.context.characteristicClass.digits | 
        
        
           | 
                      except AttributeError: | 
        
        
           | 
                          raise TypeError("Invalid Context object") | 
        
        
           | 
                      else: | 
        
        
           | 
                          ox = other.dec | 
        
        
           | 
                          c = other.context | 
        
        
           | 
                  else: | 
        
        
           | 
                      ox = other.dec_value | 
        
        
           | 
                      c = other | 
        
        
           | 
                  if other_sig_digits != self.significand.digits or \ | 
        
        
           | 
                     other_char_digits != self.characteristic.digits: | 
        
        
           | 
                      raise ValueError("Mismatched precision") | 
        
        
           | 
                  elif c.round_mode != self.round_mode: | 
        
        
           | 
                      raise ValueError("Mismatched rounding modes") | 
        
        
           | 
                  return ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __eq__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.dec_value == ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __ne__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.dec_value != ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __le__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.dec_value <= ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __lt__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.dec_value < ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __ge__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.dec_value >= ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __gt__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.dec_value > ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __neg__(self): | 
        
        
           | 
                  return self.__class__(str(1-self.signbit.dec_value) + str(self)[1:]) | 
        
        
           | 
          
 | 
        
        
           | 
              def __abs__(self): | 
        
        
           | 
                  return self.__class__('0' + str(self)[1:]) | 
        
        
           | 
          
 | 
        
        
           | 
              def __add__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec_value + ox) | 
        
        
           | 
          
 | 
        
        
           | 
              __radd__ = __add__ | 
        
        
           | 
          
 | 
        
        
           | 
              def __sub__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec_value - ox) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rsub__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(ox - self.dec_value) | 
        
        
           | 
          
 | 
        
        
           | 
              def __mul__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec_value * ox) | 
        
        
           | 
          
 | 
        
        
           | 
              __rmul__ = __mul__ | 
        
        
           | 
          
 | 
        
        
           | 
              def __div__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec_value / ox) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rdiv__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(ox / self.dec_value) | 
        
        
           | 
          
 | 
        
        
           | 
              __rtruediv__ = __rdiv__ | 
        
        
           | 
          
 | 
        
        
           | 
              def __pow__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec_value ** ox) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rpow__(self, other): | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  return self.__class__(ox ** self.dec_value) | 
        
        
           | 
          
 | 
        
        
           | 
              def sqrt(self): | 
        
        
           | 
                  return self.__class__(self.dec_value.sqrt()) | 
        
        
           | 
          
 | 
        
        
           | 
              def __nonzero__(self): | 
        
        
           | 
                  return self.dec_value != 0 | 
        
        
           | 
          
 | 
        
        
           | 
              def max(self, other): | 
        
        
           | 
                  """Respects NaN and Inf""" | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  r = self.dec_value.max(ox) | 
        
        
           | 
                  if r == self.dec_value: | 
        
        
           | 
                      return self | 
        
        
           | 
                  else: | 
        
        
           | 
                      return other | 
        
        
           | 
          
 | 
        
        
           | 
              def min(self, other): | 
        
        
           | 
                  """Respects NaN and Inf""" | 
        
        
           | 
                  ox = self._op_check(other) | 
        
        
           | 
                  r = self.dec_value.min(ox) | 
        
        
           | 
                  if r == self.dec_value: | 
        
        
           | 
                      return self | 
        
        
           | 
                  else: | 
        
        
           | 
                      return other | 
        
        
           | 
          
 | 
        
        
           | 
              def __copy__(self): | 
        
        
           | 
                  if type(self) == ContextClass: | 
        
        
           | 
                      return self     # I'm immutable; therefore I am my own clone | 
        
        
           | 
                  return self.__class__(str(self)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __deepcopy__(self, memo): | 
        
        
           | 
                  if type(self) == ContextClass: | 
        
        
           | 
                      return self     # My components are also immutable | 
        
        
           | 
                  return self.__class__(str(self)) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          class context_registry(object): | 
        
        
           | 
              """Registry saves re-creating temporary copies of the same context classes | 
        
        
           | 
              during eval() calls, etc., by keeping a registry of all created | 
        
        
           | 
              contexts in the present session. | 
        
        
           | 
              """ | 
        
        
           | 
              def __init__(self): | 
        
        
           | 
                  self.contexts = {} | 
        
        
           | 
          
 | 
        
        
           | 
              def __call__(self, char_digits, sig_digits, rounding=ROUND_HALF_UP): | 
        
        
           | 
                  try: | 
        
        
           | 
                      return self.contexts[(char_digits, sig_digits, rounding)] | 
        
        
           | 
                  except KeyError: | 
        
        
           | 
                      return self.make_context(char_digits, sig_digits, rounding) | 
        
        
           | 
          
 | 
        
        
           | 
              def make_context(self, char_digits, sig_digits, rounding): | 
        
        
           | 
                  """Class factory for binary float arithmetic using the given number of | 
        
        
           | 
                  digits for the characteristic (exponent) and significand (mantissa, or | 
        
        
           | 
                  fraction). | 
        
        
           | 
          
 | 
        
        
           | 
                  rounding type defaults to rounding up (away from 0). | 
        
        
           | 
                  """ | 
        
        
           | 
                  if rounding not in _round_code: | 
        
        
           | 
                      raise ValueError("Invalid rounding type specified") | 
        
        
           | 
          
 | 
        
        
           | 
                  class CharacteristicClass(BinaryCharacteristic): | 
        
        
           | 
                      digits = char_digits | 
        
        
           | 
                      largest = 2**char_digits-1 | 
        
        
           | 
                      bias = 2**(char_digits-1)-1 | 
        
        
           | 
                      exp_largest = 2**(char_digits-1) | 
        
        
           | 
                      exp_lowest = -2**(char_digits-1) + 1 | 
        
        
           | 
          
 | 
        
        
           | 
                  class SignificandClass(BinarySignificand): | 
        
        
           | 
                      digits = sig_digits | 
        
        
           | 
                      largest = 2**sig_digits-1 | 
        
        
           | 
          
 | 
        
        
           | 
                  class context(ContextClass): | 
        
        
           | 
                      characteristicClass = CharacteristicClass | 
        
        
           | 
                      significandClass = SignificandClass | 
        
        
           | 
                      largest_denorm = (Decimal(2) ** Decimal(-2**(char_digits-1)+2) ) * \ | 
        
        
           | 
                                          (1 - Decimal(2)**(-sig_digits)) | 
        
        
           | 
                      largest_norm = (1 - Decimal("0.5")**(sig_digits+1)) * \ | 
        
        
           | 
                                            2 ** (2**(char_digits - 1)) | 
        
        
           | 
                      digits = 1 + char_digits + sig_digits | 
        
        
           | 
                      round_mode = rounding | 
        
        
           | 
                      Etop = 2**(char_digits-1) | 
        
        
           | 
                      Etiny = -2**(char_digits-1) + 1 | 
        
        
           | 
          
 | 
        
        
           | 
                  context.__name__ = "Float_%d_%d_%s" % (char_digits, sig_digits, | 
        
        
           | 
                                                 _round_code[rounding]) | 
        
        
           | 
          
 | 
        
        
           | 
                  self.contexts[(char_digits, sig_digits, rounding)] = context | 
        
        
           | 
                  return context | 
        
        
           | 
          
 | 
        
        
           | 
          define_context = context_registry() | 
        
        
           | 
          
 | 
        
        
           | 
          single = define_context(8, 23)  # IEEE 754 32 bit float | 
        
        
           | 
          double = define_context(11, 52)  # IEEE 754 64 bit float | 
        
        
           | 
          quadruple = define_context(15, 112)  # IEEE 754 128 bit float | 
        
        
           | 
          half = define_context(5, 10)  # IEEE 754 16 bit float | 
        
        
           | 
          
 | 
        
        
           | 
          test = define_context(4, 6, ROUND_DOWN)  # for learning purposes | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          class Binary(object): | 
        
        
           | 
              """Constructor for binary floating point representation from a binary string | 
        
        
           | 
              or Decimal class representation of a real number: e.g. -1101.100011 or | 
        
        
           | 
              Decimal("-13.546875000"). The value may also be an instance of an existing | 
        
        
           | 
              context. | 
        
        
           | 
          
 | 
        
        
           | 
              If a context is given as a Context class, the return value will be an | 
        
        
           | 
              instance of that class (a IEEE 754 representation of that binary value). | 
        
        
           | 
              If the value given was from a different context it will be coerced. | 
        
        
           | 
          
 | 
        
        
           | 
              The context may also be provided as the tuple: (characteristic_digits, | 
        
        
           | 
                                                              significand_digits, | 
        
        
           | 
                                                              rounding mode string) | 
        
        
           | 
              although this is intended primarily for internal use or for eval(repr(x)) | 
        
        
           | 
              for a Context object x. | 
        
        
           | 
          
 | 
        
        
           | 
              Binary() is the same as Binary('0') to be functionally compatible with | 
        
        
           | 
              the Decimal class. | 
        
        
           | 
              """ | 
        
        
           | 
              def __init__(self, x='0', context=None): | 
        
        
           | 
                  if isinstance(context, tuple): | 
        
        
           | 
                      self.context = define_context(context[0], context[1], | 
        
        
           | 
                                                    rounding=context[2]) | 
        
        
           | 
                  else: | 
        
        
           | 
                      self.context = context | 
        
        
           | 
          
 | 
        
        
           | 
                  # placeholder for representation of x | 
        
        
           | 
                  self.rep = None | 
        
        
           | 
          
 | 
        
        
           | 
                  if isinstance(x, Binary): | 
        
        
           | 
                      self.dec = x.dec | 
        
        
           | 
                      self.bin = x.bin | 
        
        
           | 
                      if context is None: | 
        
        
           | 
                          self.context = x.context | 
        
        
           | 
                          # in case x.context is not None (otherwise gets | 
        
        
           | 
                          # overwritten by x.dec == x.rep anyway) | 
        
        
           | 
                          self.rep = x.rep | 
        
        
           | 
                  elif isinstance(x, ContextClass): | 
        
        
           | 
                      if context is None: | 
        
        
           | 
                          # optimization -- don't recreate self.rep later | 
        
        
           | 
                          # from this context, keep it now. | 
        
        
           | 
                          self.context = x.__class__ | 
        
        
           | 
                          self.rep = x | 
        
        
           | 
                          self.dec = x.as_decimal() | 
        
        
           | 
                          self.bin = str(x.as_binary()) | 
        
        
           | 
                      else: | 
        
        
           | 
                          x_dec = x.as_decimal() | 
        
        
           | 
                          if abs(x_dec) > self.context.largest_norm: | 
        
        
           | 
                              if x_dec < 0: | 
        
        
           | 
                                  self.bin = "-Inf" | 
        
        
           | 
                                  seld.dec = Decimal("-Inf") | 
        
        
           | 
                              else: | 
        
        
           | 
                                  self.bin = "Inf" | 
        
        
           | 
                                  self.dec = Decimal("Inf") | 
        
        
           | 
                              self.rep = self.context(self.dec) | 
        
        
           | 
                  elif isinstance(x, Decimal): | 
        
        
           | 
                      self.dec = x | 
        
        
           | 
                      if self.context is None: | 
        
        
           | 
                          raise ValueError("Cannot create arbitrary precision binary " | 
        
        
           | 
                                           "value without a representation context") | 
        
        
           | 
                      if x._isnan() or x._isinfinity() != 0: | 
        
        
           | 
                          if x._isnan(): | 
        
        
           | 
                              self.bin = "NaN" | 
        
        
           | 
                          else: | 
        
        
           | 
                              if x < 0: | 
        
        
           | 
                                  self.bin = "-Inf" | 
        
        
           | 
                              else: | 
        
        
           | 
                                  self.bin = "Inf" | 
        
        
           | 
                      elif abs(x) > self.context.largest_norm: | 
        
        
           | 
                          if x < 0: | 
        
        
           | 
                              self.dec = Decimal("-Inf") | 
        
        
           | 
                              self.bin = "-Inf" | 
        
        
           | 
                          else: | 
        
        
           | 
                              self.dec = Decimal("Inf") | 
        
        
           | 
                              self.bin = "Inf" | 
        
        
           | 
                      else: | 
        
        
           | 
                          self.bin = dec2binstr(x, self.context) | 
        
        
           | 
                  else: | 
        
        
           | 
                      # string | 
        
        
           | 
                      bstr = x.lower() | 
        
        
           | 
                      if bstr in ['-inf', 'inf', 'nan']: | 
        
        
           | 
                          self.bin = x | 
        
        
           | 
                          self.dec = Decimal(x) | 
        
        
           | 
                      else: | 
        
        
           | 
                          self.bin = x | 
        
        
           | 
                          self.dec = binvalstr2dec(bstr) | 
        
        
           | 
          
 | 
        
        
           | 
                  if self.context is None: | 
        
        
           | 
                      self.rep = self.dec | 
        
        
           | 
                  else: | 
        
        
           | 
                      if self.rep is None: | 
        
        
           | 
                          try: | 
        
        
           | 
                              self.rep = self.context(self.dec) | 
        
        
           | 
                          except BinaryOverflow: | 
        
        
           | 
                              if self.dec < 0: | 
        
        
           | 
                                  self.dec = Decimal("-Inf") | 
        
        
           | 
                                  self.bin = "-Inf" | 
        
        
           | 
                              else: | 
        
        
           | 
                                  self.dec = Decimal("Inf") | 
        
        
           | 
                                  self.bin = "Inf" | 
        
        
           | 
                              self.rep = self.context(self.dec) | 
        
        
           | 
                      self.dec = self.rep.dec_value | 
        
        
           | 
                      if self.rep.bin_value == "": | 
        
        
           | 
                          # lazy evaluation hasn't been performed yet | 
        
        
           | 
                          self.bin = dec2binstr(self.dec, self.rep) | 
        
        
           | 
                          # might as well update the representation | 
        
        
           | 
                          self.rep.bin_value = self.bin | 
        
        
           | 
                      else: | 
        
        
           | 
                          self.bin = self.rep.bin_value | 
        
        
           | 
          
 | 
        
        
           | 
              def __hash__(self): | 
        
        
           | 
                  return hash(self.rep) | 
        
        
           | 
          
 | 
        
        
           | 
              def __str__(self): | 
        
        
           | 
                  return self.bin | 
        
        
           | 
          
 | 
        
        
           | 
              def __repr__(self): | 
        
        
           | 
                  if self.context: | 
        
        
           | 
                      return 'Binary("%s", (%d, %d, %s))' % (self.bin, | 
        
        
           | 
                                  self.context.characteristicClass.digits, | 
        
        
           | 
                                  self.context.significandClass.digits, | 
        
        
           | 
                                  self.context.round_mode) | 
        
        
           | 
                  else: | 
        
        
           | 
                      return 'Binary("%s")' % self.bin | 
        
        
           | 
          
 | 
        
        
           | 
              def as_binary(self): | 
        
        
           | 
                  return self | 
        
        
           | 
          
 | 
        
        
           | 
              def as_decimal(self): | 
        
        
           | 
                  return self.dec | 
        
        
           | 
          
 | 
        
        
           | 
              def _op_check(self, other): | 
        
        
           | 
                  if isinstance(other, (int, long, npy.int32, npy.int64)): | 
        
        
           | 
                      ox, c = Decimal(other), None | 
        
        
           | 
                  elif isinstance(other, Binary): | 
        
        
           | 
                      ox, c = other.dec, other.context | 
        
        
           | 
                  elif isinstance(other, Decimal): | 
        
        
           | 
                      ox, c = other, None | 
        
        
           | 
                  elif isinstance(other, ContextClass): | 
        
        
           | 
                      # ContextClass is strict about comparing only with others | 
        
        
           | 
                      # of the same representation, so ensure self is | 
        
        
           | 
                      if self.context == other.__class__: | 
        
        
           | 
                          ox, c = other.as_decimal(), other.__class__ | 
        
        
           | 
                      else: | 
        
        
           | 
                          raise TypeError("Invalid object for comparison") | 
        
        
           | 
                  else: | 
        
        
           | 
                      raise TypeError("Invalid object for comparison") | 
        
        
           | 
                  if self.context: | 
        
        
           | 
                      s_digits = self.context.digits | 
        
        
           | 
                  else: | 
        
        
           | 
                      s_digits = 0 | 
        
        
           | 
                  if c: | 
        
        
           | 
                      c_digits = c.digits | 
        
        
           | 
                  else: | 
        
        
           | 
                      c_digits = 0 | 
        
        
           | 
                  if s_digits > c_digits: | 
        
        
           | 
                      ctx = self.context | 
        
        
           | 
                  else: | 
        
        
           | 
                      if s_digits > 0 and s_digits == c_digits: | 
        
        
           | 
                          # contexts have the same precision, but what about | 
        
        
           | 
                          # rounding? | 
        
        
           | 
                          if self.context.round_mode == c.round_mode: | 
        
        
           | 
                              ctx = c | 
        
        
           | 
                          else: | 
        
        
           | 
                              raise ValueError("Clash of rounding modes for " | 
        
        
           | 
                                               "equal-precision comparison") | 
        
        
           | 
                      else: | 
        
        
           | 
                          ctx = c | 
        
        
           | 
                  return ox, ctx | 
        
        
           | 
          
 | 
        
        
           | 
              def __eq__(self, other): | 
        
        
           | 
                  ox, c = self._op_check(other) | 
        
        
           | 
                  return self.dec == ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __ne__(self, other): | 
        
        
           | 
                  ox, c = self._op_check(other) | 
        
        
           | 
                  return self.dec != ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __le__(self, other): | 
        
        
           | 
                  ox, c = self._op_check(other) | 
        
        
           | 
                  return self.dec <= ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __lt__(self, other): | 
        
        
           | 
                  ox, c = self._op_check(other) | 
        
        
           | 
                  return self.dec < ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __ge__(self, other): | 
        
        
           | 
                  ox, c = self._op_check(other) | 
        
        
           | 
                  return self.dec >= ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __gt__(self, other): | 
        
        
           | 
                  ox, c = self._op_check(other) | 
        
        
           | 
                  return self.dec > ox | 
        
        
           | 
          
 | 
        
        
           | 
              def __neg__(self): | 
        
        
           | 
                  return self.__class__(-self.rep) | 
        
        
           | 
          
 | 
        
        
           | 
              def __abs__(self): | 
        
        
           | 
                  return self.__class__(abs(self.rep)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __add__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec + ox, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              __radd__ = __add__ | 
        
        
           | 
          
 | 
        
        
           | 
              def __sub__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec - ox, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rsub__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(ox - self.dec, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              def __mul__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec * ox, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              __rmul__ = __mul__ | 
        
        
           | 
          
 | 
        
        
           | 
              def __div__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec / ox, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rdiv__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(ox / self.dec, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              __rtruediv__ = __rdiv__ | 
        
        
           | 
          
 | 
        
        
           | 
              def __pow__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(self.dec ** ox, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              def __rpow__(self, other): | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  return self.__class__(ox ** self.dec, ctx) | 
        
        
           | 
          
 | 
        
        
           | 
              def __nonzero__(self): | 
        
        
           | 
                  return self.dec != 0 | 
        
        
           | 
          
 | 
        
        
           | 
              def sqrt(self): | 
        
        
           | 
                  return self.__class__(self.dec.sqrt(), self.context) | 
        
        
           | 
          
 | 
        
        
           | 
              def max(self, other): | 
        
        
           | 
                  """Respects NaN and Inf""" | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  r = self.dec.max(ox) | 
        
        
           | 
                  if r == self.dec: | 
        
        
           | 
                      return self | 
        
        
           | 
                  else: | 
        
        
           | 
                      return other | 
        
        
           | 
          
 | 
        
        
           | 
              def min(self, other): | 
        
        
           | 
                  """Respects NaN and Inf""" | 
        
        
           | 
                  ox, ctx = self._op_check(other) | 
        
        
           | 
                  r = self.dec.min(ox) | 
        
        
           | 
                  if r == self.dec: | 
        
        
           | 
                      return self | 
        
        
           | 
                  else: | 
        
        
           | 
                      return other | 
        
        
           | 
          
 | 
        
        
           | 
              def __reduce__(self): | 
        
        
           | 
                  return (self.__class__, (repr(self),)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __copy__(self): | 
        
        
           | 
                  if type(self) == Binary: | 
        
        
           | 
                      return self     # I'm immutable; therefore I am my own clone | 
        
        
           | 
                  return self.__class__(str(self)) | 
        
        
           | 
          
 | 
        
        
           | 
              def __deepcopy__(self, memo): | 
        
        
           | 
                  if type(self) == Binary: | 
        
        
           | 
                      return self     # My components are also immutable | 
        
        
           | 
                  return self.__class__(str(self)) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def binvalstr2dec(x): | 
        
        
           | 
              """Convert signed real numbers in binary string form to decimal | 
        
        
           | 
              value (no special values Inf, NaN), including values in scientific notation. | 
        
        
           | 
              """ | 
        
        
           | 
              if not isbinstr(x): | 
        
        
           | 
                  raise ValueError("Invalid string representation of binary" | 
        
        
           | 
                                       " float: %s" % x) | 
        
        
           | 
              if x[0] == '-': | 
        
        
           | 
                  x = x[1:] | 
        
        
           | 
                  sign = -1 | 
        
        
           | 
              else: | 
        
        
           | 
                  sign = 1 | 
        
        
           | 
              if 'e' in x: | 
        
        
           | 
                  x, estr = x.split('e') | 
        
        
           | 
                  e = int(estr) | 
        
        
           | 
              elif 'E' in x: | 
        
        
           | 
                  x, estr = x.split('E') | 
        
        
           | 
                  e = int(estr) | 
        
        
           | 
              else: | 
        
        
           | 
                  e = 0 | 
        
        
           | 
              if '.' in x: | 
        
        
           | 
                  try: | 
        
        
           | 
                      whole, frac = x.split('.') | 
        
        
           | 
                  except ValueError: | 
        
        
           | 
                      raise ValueError("Invalid string representation of binary" | 
        
        
           | 
                                       " float") | 
        
        
           | 
                  else: | 
        
        
           | 
                      if frac == "": | 
        
        
           | 
                          frac = '0' | 
        
        
           | 
                      if whole == "": | 
        
        
           | 
                          whole = '0' | 
        
        
           | 
              else: | 
        
        
           | 
                  whole = x | 
        
        
           | 
                  frac = '0' | 
        
        
           | 
              try: | 
        
        
           | 
                  dec_whole = Decimal(int(whole, base=2)) * Decimal(2)**e | 
        
        
           | 
              except ValueError: | 
        
        
           | 
                  dec_whole = Decimal(0) | 
        
        
           | 
              dec_frac = binfracstr2decfrac(frac) * Decimal(2)**e | 
        
        
           | 
              return sign*(dec_whole+dec_frac) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def isbinstr(arg): | 
        
        
           | 
              # supports unary + / - at front, and checks for usage of exponentials | 
        
        
           | 
              # (using 'E' or 'e') | 
        
        
           | 
              s = arg.lower() | 
        
        
           | 
              try: | 
        
        
           | 
                  if s[0] in ['+','-']: | 
        
        
           | 
                      s_rest = s[1:] | 
        
        
           | 
                  else: | 
        
        
           | 
                      s_rest = s | 
        
        
           | 
              except IndexError: | 
        
        
           | 
                  return False | 
        
        
           | 
              if '0' not in s_rest and '1' not in s_rest: | 
        
        
           | 
                  return False | 
        
        
           | 
              pts = s.count('.') | 
        
        
           | 
              exps = s.count('e') | 
        
        
           | 
              pm = s_rest.count('+') + s_rest.count('-') | 
        
        
           | 
              if pts > 1 or exps > 1 or pm > 1: | 
        
        
           | 
                  return False | 
        
        
           | 
              if exps == 1: | 
        
        
           | 
                  exp_pos = s.find('e') | 
        
        
           | 
                  pre_exp = s[:exp_pos] | 
        
        
           | 
                  # must be numbers before and after the 'e' | 
        
        
           | 
                  if not npy.sometrue([n in ('0','1') for n in pre_exp]): | 
        
        
           | 
                      return False | 
        
        
           | 
                  if s[-1]=='e': | 
        
        
           | 
                      # no chars after 'e'! | 
        
        
           | 
                      return False | 
        
        
           | 
                  if not npy.sometrue([n in ('0','1','2','3','4','5','6','7','8','9') \ | 
        
        
           | 
                                       for n in s[exp_pos:]]): | 
        
        
           | 
                      return False | 
        
        
           | 
                  # check that any additional +/- occurs directly after 'e' | 
        
        
           | 
                  if pm == 1: | 
        
        
           | 
                      pm_pos = max([s_rest.find('+'), s_rest.find('-')]) | 
        
        
           | 
                      if s_rest[pm_pos-1] != 'e': | 
        
        
           | 
                          return False | 
        
        
           | 
                      e_rest = s_rest[pm_pos+1:]   # safe due to previous check | 
        
        
           | 
                      s_rest = s_rest[:pm_pos+1] | 
        
        
           | 
                  else: | 
        
        
           | 
                      e_rest = s[exp_pos+1:] | 
        
        
           | 
                      s_rest = s[:exp_pos+1] | 
        
        
           | 
                  # only remaining chars in s after e and possible +/- are numbers | 
        
        
           | 
                  if '.' in e_rest: | 
        
        
           | 
                      return False | 
        
        
           | 
              # cannot use additional +/- if not using exponent | 
        
        
           | 
              if pm == 1 and exps == 0: | 
        
        
           | 
                  return False | 
        
        
           | 
              return npy.alltrue([n in ('0', '1', '.', 'e', '+', '-') for n in s_rest]) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def binstr2dec(bstr): | 
        
        
           | 
              """Convert binary string representation of an integer to a decimal integer. | 
        
        
           | 
              """ | 
        
        
           | 
              return int(bstr, base=2) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def decint2binstr(n): | 
        
        
           | 
              """Convert decimal integer to binary string. | 
        
        
           | 
              """ | 
        
        
           | 
              if n < 0: | 
        
        
           | 
                  return '-' + decint2binstr(-n) | 
        
        
           | 
              s = '' | 
        
        
           | 
              while n != 0: | 
        
        
           | 
                  s = str(n % 2) + s | 
        
        
           | 
                  n >>= 1 | 
        
        
           | 
              return s or '0' | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def binfracstr2decfrac(bstr): | 
        
        
           | 
              """Convert non-negative binary string fraction (without radix) to decimal | 
        
        
           | 
              fraction. | 
        
        
           | 
              e.g. to convert ".1101", binfracstr2decfrac('1101') -> Decimal("0.8125") | 
        
        
           | 
              """ | 
        
        
           | 
              assert bstr[0] != '-', "Only pass non-negative values" | 
        
        
           | 
              dec_value = 0 | 
        
        
           | 
              half = Decimal("0.5") | 
        
        
           | 
              for place, bit in enumerate(bstr): | 
        
        
           | 
                  if int(bit) == 1: | 
        
        
           | 
                      dec_value += half**(place+1) | 
        
        
           | 
              return dec_value | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def frexp(d, context): | 
        
        
           | 
              """Implementation of 'frexp' for arbitrary precision decimals. | 
        
        
           | 
              Result is a pair F, E, where 0 < F < 1 is a Decimal object, | 
        
        
           | 
              and E is a signed integer such that | 
        
        
           | 
          
 | 
        
        
           | 
              d = F * 2**E | 
        
        
           | 
          
 | 
        
        
           | 
              context specifies the maximum absolute value of the exponent | 
        
        
           | 
              to ensure termination of the calculation. e.g. for double precision | 
        
        
           | 
              pass the 'double' Context class which defines a characteristic | 
        
        
           | 
              of 11 bits, with maximum exponent size of 1024. | 
        
        
           | 
              """ | 
        
        
           | 
              e_largest = context.characteristicClass.exp_largest | 
        
        
           | 
              if d < 0: | 
        
        
           | 
                  res = frexp(-d, e_largest) | 
        
        
           | 
                  return -res[0], res[1] | 
        
        
           | 
          
 | 
        
        
           | 
              elif d == 0: | 
        
        
           | 
                  return Decimal("0"), 0 | 
        
        
           | 
          
 | 
        
        
           | 
              elif d >= 1: | 
        
        
           | 
                  w_dec = int(d) | 
        
        
           | 
                  e_dec = 0 | 
        
        
           | 
                  while w_dec > 0 and abs(e_dec) <= e_largest: | 
        
        
           | 
                      d /= 2 | 
        
        
           | 
                      w_dec = int(d) | 
        
        
           | 
                      e_dec += 1 | 
        
        
           | 
                  return d, e_dec | 
        
        
           | 
          
 | 
        
        
           | 
              else: | 
        
        
           | 
                  # 0 < d < 1 | 
        
        
           | 
                  w_dec = 0 | 
        
        
           | 
                  e_dec = 0 | 
        
        
           | 
                  while w_dec == 0 and abs(e_dec) <= e_largest: | 
        
        
           | 
                      w_dec = int(d*2) | 
        
        
           | 
                      if w_dec > 0: | 
        
        
           | 
                          break | 
        
        
           | 
                      else: | 
        
        
           | 
                          d *= 2 | 
        
        
           | 
                          e_dec -= 1 | 
        
        
           | 
                  return d, e_dec | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def dec2binstr(x, context=None): | 
        
        
           | 
              if x < 0: | 
        
        
           | 
                  signstr = '-' | 
        
        
           | 
                  valstr = -x | 
        
        
           | 
              elif x == 0: | 
        
        
           | 
                  return '0.0' | 
        
        
           | 
              else: | 
        
        
           | 
                  signstr = '' | 
        
        
           | 
                  valstr = x | 
        
        
           | 
              # convert to binary fraction representation | 
        
        
           | 
              e, f = decfrac2binrep(valstr, context) | 
        
        
           | 
              return signstr + '0.' + f + 'E' + str(int(e, base=2)) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def decfrac2binrep(x, context): | 
        
        
           | 
              """Convert positive decimal float to the nearest representable | 
        
        
           | 
              "<characteristic> <significand>" binary string representation (natural | 
        
        
           | 
              format, where characteristic may be negative), using an exponent no bigger | 
        
        
           | 
              than permitted in the given context. | 
        
        
           | 
          
 | 
        
        
           | 
              """ | 
        
        
           | 
              assert x > 0, "Provide only positive Decimal float value" | 
        
        
           | 
              assert isinstance(x, Decimal), "Provide only positive Decimal float value" | 
        
        
           | 
              fraction, exponent = frexp(x, context) | 
        
        
           | 
              max_bits = context.characteristicClass.exp_largest + \ | 
        
        
           | 
                           context.significandClass.digits | 
        
        
           | 
              bfrac = npy.zeros(max_bits, int) | 
        
        
           | 
              i = 0 | 
        
        
           | 
              i_stop = max_bits | 
        
        
           | 
              not_seen_one = True | 
        
        
           | 
              while fraction > 0 and i < max_bits: | 
        
        
           | 
                  fraction *= 2 | 
        
        
           | 
                  bit = int(fraction) | 
        
        
           | 
                  if not_seen_one and bit == 1: | 
        
        
           | 
                      # speed optimization | 
        
        
           | 
                      i_stop  = i + context.significandClass.digits + 2 | 
        
        
           | 
                  bfrac[i] = bit | 
        
        
           | 
                  fraction -= bit | 
        
        
           | 
                  i += 1 | 
        
        
           | 
                  if i >= i_stop: | 
        
        
           | 
                      break | 
        
        
           | 
              # negative exponents OK for this usage | 
        
        
           | 
              return decint2binstr(exponent), "".join([str(bit) for \ | 
        
        
           | 
                                                       bit in bfrac[:i]]) | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          def pad(value, digits, to_right=False): | 
        
        
           | 
              """Only use for positive binary numbers given as strings. | 
        
        
           | 
              Pads to the left by default, or to the right using to_right flag. | 
        
        
           | 
          
 | 
        
        
           | 
              Inputs: value -- string of bits | 
        
        
           | 
                      digits -- number of bits in representation | 
        
        
           | 
                      to_right -- Boolean, direction of padding | 
        
        
           | 
          
 | 
        
        
           | 
              Output: string of bits of length 'digits' | 
        
        
           | 
          
 | 
        
        
           | 
              Raises exception if value is larger than digits in length. | 
        
        
           | 
          
 | 
        
        
           | 
              Example: | 
        
        
           | 
                pad('0010', 6) -> '000010' | 
        
        
           | 
                pad('0010', 6, True) -> '001000' | 
        
        
           | 
              """ | 
        
        
           | 
              len_val = len(value) | 
        
        
           | 
              assert len_val <= digits | 
        
        
           | 
              rem_digits = digits - len_val | 
        
        
           | 
              if to_right: | 
        
        
           | 
                  return value + "0"*rem_digits | 
        
        
           | 
              else: | 
        
        
           | 
                  return "0"*rem_digits + value | 
        
        
           | 
          
 | 
        
        
           | 
          def bin_sign(x): | 
        
        
           | 
              """Binary representation of sign: x < 0 is represented as 1, 0 otherwise. | 
        
        
           | 
              """ | 
        
        
           | 
              s=npy.sign(x) | 
        
        
           | 
              if s >= 0: | 
        
        
           | 
                  return 0 | 
        
        
           | 
              else: | 
        
        
           | 
                  return 1 | 
        
        
           | 
          
 | 
        
        
           | 
          
 | 
        
        
           | 
          ## exceptions | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryException(ArithmeticError): | 
        
        
           | 
              def __init__(self, value=None): | 
        
        
           | 
                  self.value = value | 
        
        
           | 
                  self.code = None | 
        
        
           | 
          
 | 
        
        
           | 
              def __str__(self): | 
        
        
           | 
                  return repr(self.value) | 
        
        
           | 
          
 | 
        
        
           | 
              def __repr__(self): | 
        
        
           | 
                  return repr(self.value) | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryOverflow(BinaryException): | 
        
        
           | 
              pass | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryUnderflow(BinaryException): | 
        
        
           | 
              pass | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryNegativeValue(BinaryException): | 
        
        
           | 
              pass | 
        
        
           | 
          
 | 
        
        
           | 
          class BinaryRemainderValue(BinaryException): | 
        
        
           | 
              pass |