[Python-checkins] python/nondist/sandbox/decimal Decimal.py, 1.12, 1.13 test_Decimal.py, 1.5, 1.6

eprice at users.sourceforge.net eprice at users.sourceforge.net
Fri Feb 6 11:31:35 EST 2004


Update of /cvsroot/python/python/nondist/sandbox/decimal
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12521

Modified Files:
	Decimal.py test_Decimal.py 
Log Message:
Updated to pass newer test cases.  Most notably, NaNs with diagnostic info work.



Index: Decimal.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/decimal/Decimal.py,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** Decimal.py	12 Aug 2003 23:04:23 -0000	1.12
--- Decimal.py	6 Feb 2004 16:31:32 -0000	1.13
***************
*** 248,252 ****
      def handle(self, context, *args):
          if args:
!             return (NaN,NaN)
          return NaN
  
--- 248,253 ----
      def handle(self, context, *args):
          if args:
!             if args[0] == 1: #sNaN, must drop 's' but keep diagnostics
!                 return Decimal( (args[1]._sign, args[1]._int, 'n') )
          return NaN
  
***************
*** 374,377 ****
--- 375,382 ----
  ExceptionList = filter(filterfunct, globals().values())
  
+ #To fix reloading, force it to create a new context
+ #Old contexts have different exceptions in their dicts, making problems.
+ if hasattr(threading.currentThread(), '__decimal_context__'):
+     del threading.currentThread().__decimal_context__
  
  def setcontext(context):
***************
*** 423,433 ****
                  return
              if isnan(value):
!                 sig = isnan(value) - 1
!                 self._exp = sig and 'N' or 'n'
!                 self._sign = 0
!                 self._int = (0,) #snan or nan
                  return
              self._convertString(value, context)
-             # Only a string if it works here
              return
  
--- 428,444 ----
                  return
              if isnan(value):
!                 sig, sign, diag = isnan(value)
!                 if len(diag) > context.prec: #Diagnostic info too long
!                     self._sign, self._int, self._exp = \
!                                 context.raise_error(ConversionSyntax)
!                     return
!                 if sig == 1:
!                     self._exp = 'n' #qNaN
!                 else: #sig == 2
!                     self._exp = 'N' #sNaN
!                 self._sign = sign
!                 self._int = tuple(map(int, tuple(diag))) #Diagnostic info
                  return
              self._convertString(value, context)
              return
  
***************
*** 441,452 ****
                  raise ValueError, 'Invalid arguments'
              if value[0] not in [0,1]:
!               raise ValueError, 'Invalid sign'
              # FIXME: Add more input validation checks here
              self._sign = value[0]
              self._int  = tuple(value[1])
              if value[2] in ('F','n','N'):
!               self._exp = value[2]
              else:
!               self._exp  = long(value[2])
              return
  
--- 452,464 ----
                  raise ValueError, 'Invalid arguments'
              if value[0] not in [0,1]:
!                 raise ValueError, 'Invalid sign'
!             
              # FIXME: Add more input validation checks here
              self._sign = value[0]
              self._int  = tuple(value[1])
              if value[2] in ('F','n','N'):
!                 self._exp = value[2]
              else:
!                 self._exp  = long(value[2])
              return
  
***************
*** 468,472 ****
  
          if isinstance(value, float):
!             #self._convertString(_floatToString(value), context)
              #
              # This would give a more strictly accurate representation,
--- 480,485 ----
  
          if isinstance(value, float):
!             # Another possibility would be:
!             #   self._convertString(_floatToString(value), context)
              #
              # This would give a more strictly accurate representation,
***************
*** 521,531 ****
  
          if self._isnan() == 2:
!             return context.raise_error(InvalidOperation, 'sNaN')
          if other is not None and other._isnan() == 2:
!             return context.raise_error(InvalidOperation, 'sNaN')
          if self._isnan():
!             return NaN
          if other is not None and other._isnan():
!             return NaN
          return 0
  
--- 534,546 ----
  
          if self._isnan() == 2:
!             return context.raise_error(InvalidOperation, 'sNaN',
!                                        1, self)
          if other is not None and other._isnan() == 2:
!             return context.raise_error(InvalidOperation, 'sNaN',
!                                        1, other)
          if self._isnan():
!             return self
          if other is not None and other._isnan():
!             return other
          return 0
  
***************
*** 540,544 ****
              self._sign, self._int, self._exp = _string2exact(value)
          except ValueError:
!             self._sign, self._int, self._exp = context.raise_error(ConversionSyntax)
          return
  
--- 555,560 ----
              self._sign, self._int, self._exp = _string2exact(value)
          except ValueError:
!             self._sign, self._int, self._exp = \
!                         context.raise_error(ConversionSyntax)
          return
  
***************
*** 660,671 ****
          """
          if self._isnan():
              if self._isnan() == 2:
!                 return 'sNaN'
!             return 'NaN'
          if self._isinfinity():
!             sign = self._isinfinity()
!             if sign > 0:
!                 return 'Infinity'
!             return '-Infinity'
  
          if context is None:
--- 676,690 ----
          """
          if self._isnan():
+             minus = '-'*self._sign
+             if self._int == (0,):
+                 info = ''
+             else:
+                 info = ''.join(map(str, self._int))
              if self._isnan() == 2:
!                 return minus + 'sNaN' + info
!             return minus + 'NaN' + info
          if self._isinfinity():
!             minus = '-'*self._sign
!             return minus + 'Infinity'
  
          if context is None:
***************
*** 675,678 ****
--- 694,717 ----
          numdigits = len(self._int)
          leftdigits = self._exp + numdigits
+         if eng and not self: #self = 0eX wants 0[.0[0]]eY, not [[0]0]0eY
+             if self._exp < 0 and self._exp >= -6: #short, no need for e/E
+                 s = '-'*self._sign + '0.' + '0'*(abs(self._exp))
+                 return s
+             #exp is closest mult. of 3 >= self._exp
+             exp = ((self._exp - 1)// 3 + 1) * 3
+             if exp != self._exp:  
+                 s = '0.'+'0'*(exp - self._exp)
+             else:
+                 s = '0'
+             if exp != 0:
+                 if context.capitals:
+                     s += 'E'
+                 else:
+                     s += 'e'
+                 if exp > 0:
+                     s += '+' #0.0e+3, not 0.0e3
+                 s += str(exp)
+             s = '-'*self._sign + s
+             return s
          if eng:
              dotplace = (leftdigits-1)%3+1
***************
*** 900,904 ****
          if context is None:
              context = getcontext()
!         # -Decimal(0) = Decimal(0), which we don't want
          # (-0 - 0 = -0 + (-0) = -0, but -0 + 0 = 0.)
          # so we change the sign directly.
--- 939,946 ----
          if context is None:
              context = getcontext()
!         ans = self._check_nans(other, context=context)
!         if ans:
!             return ans
!         # -Decimal(0) = Decimal(0), which we don't want since
          # (-0 - 0 = -0 + (-0) = -0, but -0 + 0 = 0.)
          # so we change the sign directly.
***************
*** 1076,1079 ****
--- 1118,1123 ----
                  context.raise_error(Clamped, 'Division by infinity')
                  return Decimal((sign, (0,), context.Etiny()))
+             if self._isinfinity():
+                 return Infsign[sign]
              #These two have different precision.
              if not self:
***************
*** 1089,1105 ****
              if not other:
                  return context.raise_error(DivisionByZero, 'x / 0', sign)
-             if self._isinfinity():
-                 return Infsign[sign]
          if divmod:
              if other._isinfinity():
                  return (Decimal((sign, (0,), 0)), Decimal(self))
-             if not self:
-                 otherside = Decimal(self)
-                 otherside._exp = min(self._exp, other._exp)
-                 return (Decimal((sign, (0,), 0)),  otherside)
- 
-             if not other:
-                 return context.raise_error(DivisionByZero, 'divmod(x,0)',
-                                            sign, 1)
              if self._isinfinity():
                  if divmod == 1:
--- 1133,1139 ----
***************
*** 1111,1114 ****
--- 1145,1156 ----
                      return (Infsign[sign],
                              context.raise_error(InvalidOperation, 'INF % x'))
+             if not self:
+                 otherside = Decimal(self)
+                 otherside._exp = min(self._exp, other._exp)
+                 return (Decimal((sign, (0,), 0)),  otherside)
+ 
+             if not other:
+                 return context.raise_error(DivisionByZero, 'divmod(x,0)',
+                                            sign, 1)
  
          #OK, so neither = 0, INF
***************
*** 1121,1125 ****
  
              if divmod == 1 or divmod == 3:
!                 ans2 = Decimal(self)
                  if shouldround:
                      ans2 = ans2.fix(context=context)
--- 1163,1168 ----
  
              if divmod == 1 or divmod == 3:
!                 exp = min(self._exp, other._exp)
!                 ans2 = self.rescale(exp, context=context, watchexp=0)
                  if shouldround:
                      ans2 = ans2.fix(context=context)
***************
*** 1160,1165 ****
                                                watchexp=0)
                  context.regard_flags(*frozen)
-                 if not otherside:
-                     otherside._exp = 0
                  if shouldround:
                      otherside = otherside.fix(context=context)
--- 1203,1206 ----
***************
*** 1199,1204 ****
  
                  context.regard_flags(*frozen)
-                 if not otherside:
-                     otherside._exp = 0
  
                  return (Decimal(res), otherside)
--- 1240,1243 ----
***************
*** 1332,1336 ****
          """Converts self to a long, truncating if necessary."""
          if self._isnan():
-             
              context = getcontext()
              return context.raise_error(InvalidContext)
--- 1371,1374 ----
***************
*** 1755,1763 ****
          if context is None:
              context = getcontext()
!         if exp._isinfinity() or self._isinfinity():
!             return context.raise_error(InvalidOperation, 'quantize with an INF')
          ans = self._check_nans(exp, context)
          if ans:
              return ans
          return self.rescale(exp._exp, rounding, context, watchexp)
  
--- 1793,1806 ----
          if context is None:
              context = getcontext()
! 
          ans = self._check_nans(exp, context)
          if ans:
              return ans
+ 
+         if exp._isinfinity() or self._isinfinity():
+             if exp._isinfinity() and self._isinfinity():
+                 return self  #if both are inf, it is OK
+             return context.raise_error(InvalidOperation,
+                                        'quantize with one INF')
          return self.rescale(exp._exp, rounding, context, watchexp)
  
***************
*** 2491,2495 ****
          DEFAULT_TRAPS = BASIC_DEFAULT_TRAPS
          DEFAULT_FLAGS= BASIC_DEFAULT_FLAGS
!         DEFAULT_ROUNDING_DECISION = EXTENDED_DEFAULT_ROUNDING_DECISION
  
      elif DEFAULT_CONTEXT == EXTENDED_DEFAULT_CONTEXT:
--- 2534,2538 ----
          DEFAULT_TRAPS = BASIC_DEFAULT_TRAPS
          DEFAULT_FLAGS= BASIC_DEFAULT_FLAGS
!         DEFAULT_ROUNDING_DECISION = BASIC_DEFAULT_ROUNDING_DECISION
  
      elif DEFAULT_CONTEXT == EXTENDED_DEFAULT_CONTEXT:
***************
*** 2524,2537 ****
      """Determines whether a string or float is NaN
  
!     1 => NaN
!     2 => sNaN
      """
      if isinstance(num, float):
          num = str(num)
      num = num.lower()
!     if num == 'nan':
!         return 1
!     if num == 'snan':
!         return 2
      return 0
  
--- 2567,2594 ----
      """Determines whether a string or float is NaN
  
!     (1, sign, diagnostic info as string) => NaN
!     (2, sign, diagnostic info as string) => sNaN
!     0 => not a NaN
      """
      if isinstance(num, float):
          num = str(num)
      num = num.lower()
!     
!     #get the sign, get rid of trailing [+-]
!     sign = 0
!     if num[0] == '+':  
!         num = num[1:]
!     elif num[0] == '-':  #elif avoids '+-nan'
!         num = num[1:]
!         sign = 1
! 
!     if num.startswith('nan'):
!         if len(num) > 3 and not num[3:].isdigit(): #diagnostic info
!             return 0
!         return (1, sign, num[3:].lstrip('0'))
!     if num.startswith('snan'):
!         if len(num) > 4 and not num[4:].isdigit():
!             return 0
!         return (2, sign, num[4:].lstrip('0'))
      return 0
  

Index: test_Decimal.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/decimal/test_Decimal.py,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -d -r1.5 -r1.6
*** test_Decimal.py	12 Nov 2003 20:38:41 -0000	1.5
--- test_Decimal.py	6 Feb 2004 16:31:32 -0000	1.6
***************
*** 12,15 ****
--- 12,19 ----
  skip_expected = not os.path.isdir(dir)
  
+ # Make sure it actually raises errors when not expected and caught in flags
+ # Slower, since it runs some things several times.
+ EXTENDEDERRORTEST = False
+ 
  
  #Map the test cases' error names to the actual errors
***************
*** 158,161 ****
--- 162,178 ----
              v = FixQuotes(val)
              if fname in ('tosci', 'toeng'):
+                 if EXTENDEDERRORTEST:
+                     for error in theirexceptions:
+                         self.context.trap_enablers[error] = 1
+                         try:
+                             funct(self.context.new(v))
+                         except error:
+                             pass
+                         except ExceptionList, e:
+                             self.fail("Raised %s in %s when %s disabled" % \
+                                       (e, s, error))
+                         else:
+                             self.fail("Did not raise %s in %s" % (error, s))
+                         self.context.trap_enablers[error] = 0                
                  v = self.context.new(v)
              #elif fname == 'rescale' and i == 1:
***************
*** 169,173 ****
  
          ans = FixQuotes(ans)
! 
          try:
              result = str(funct(*vals))
--- 186,203 ----
  
          ans = FixQuotes(ans)
!         
!         if EXTENDEDERRORTEST and fname not in ('tosci', 'toeng'):
!             for error in theirexceptions:
!                 self.context.trap_enablers[error] = 1
!                 try:
!                     funct(*vals)
!                 except error:
!                     pass
!                 except ExceptionList, e:
!                     self.fail("Raised %s in %s when %s disabled" % \
!                               (e, s, error))
!                 else:
!                     self.fail("Did not raise %s in %s" % (error, s))
!                 self.context.trap_enablers[error] = 0                
          try:
              result = str(funct(*vals))
***************
*** 184,189 ****
          theirexceptions.sort()
  
!         self.assertEqual(result, ans, 'Incorrect answer for ' + s + ' -- got ' + result)
!         self.assertEqual(myexceptions, theirexceptions, 'Incorrect flags set in ' + s + ' -- got '
                           + str(myexceptions))
  
--- 214,221 ----
          theirexceptions.sort()
  
!         self.assertEqual(result, ans,
!                          'Incorrect answer for ' + s + ' -- got ' + result)
!         self.assertEqual(myexceptions, theirexceptions,
!                          'Incorrect flags set in ' + s + ' -- got ' \
                           + str(myexceptions))
  
***************
*** 268,277 ****
          self.eval_file(dir + 'inexact' + '.decTest')
  
!     #def test_integer(self):
!     #    """Tests the Decimal class on Cowlishaw's integer tests.
!     #
!     #    See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
!     #    """
!     #    self.eval_file(dir + 'integer' + '.decTest')
  
      def test_max(self):
--- 300,309 ----
          self.eval_file(dir + 'inexact' + '.decTest')
  
!     def test_integer(self):
!         """Tests the Decimal class on Cowlishaw's integer tests.
! 
!         See www2.hursley.ibm.com/decimal/decTest.zip to download the suite.
!         """
!         self.eval_file(dir + 'integer' + '.decTest')
  
      def test_max(self):




More information about the Python-checkins mailing list