Django

Code

root/django/branches/gis/django/utils/_decimal.py

Revision 5492, 103.0 kB (checked in by jdunck, 1 year ago)

gis: Merged revisions 4786-5490 via svnmerge from
http://code.djangoproject.com/svn/django/trunk

  • Property svn:eol-style set to native
Line 
1 # Copyright (c) 2004 Python Software Foundation.
2 # All rights reserved.
3
4 # Written by Eric Price <eprice at tjhsst.edu>
5 #    and Facundo Batista <facundo at taniquetil.com.ar>
6 #    and Raymond Hettinger <python at rcn.com>
7 #    and Aahz <aahz at pobox.com>
8 #    and Tim Peters
9
10 # This module is currently Py2.3 compatible and should be kept that way
11 # unless a major compelling advantage arises.  IOW, 2.3 compatibility is
12 # strongly preferred, but not guaranteed.
13
14 # Also, this module should be kept in sync with the latest updates of
15 # the IBM specification as it evolves.  Those updates will be treated
16 # as bug fixes (deviation from the spec is a compatibility, usability
17 # bug) and will be backported.  At this point the spec is stabilizing
18 # and the updates are becoming fewer, smaller, and less significant.
19
20 """
21 This is a Py2.3 implementation of decimal floating point arithmetic based on
22 the General Decimal Arithmetic Specification:
23
24     www2.hursley.ibm.com/decimal/decarith.html
25
26 and IEEE standard 854-1987:
27
28     www.cs.berkeley.edu/~ejr/projects/754/private/drafts/854-1987/dir.html
29
30 Decimal floating point has finite precision with arbitrarily large bounds.
31
32 The purpose of the module is to support arithmetic using familiar
33 "schoolhouse" rules and to avoid the some of tricky representation
34 issues associated with binary floating point.  The package is especially
35 useful for financial applications or for contexts where users have
36 expectations that are at odds with binary floating point (for instance,
37 in binary floating point, 1.00 % 0.1 gives 0.09999999999999995 instead
38 of the expected Decimal("0.00") returned by decimal floating point).
39
40 Here are some examples of using the decimal module:
41
42 >>> from decimal import *
43 >>> setcontext(ExtendedContext)
44 >>> Decimal(0)
45 Decimal("0")
46 >>> Decimal("1")
47 Decimal("1")
48 >>> Decimal("-.0123")
49 Decimal("-0.0123")
50 >>> Decimal(123456)
51 Decimal("123456")
52 >>> Decimal("123.45e12345678901234567890")
53 Decimal("1.2345E+12345678901234567892")
54 >>> Decimal("1.33") + Decimal("1.27")
55 Decimal("2.60")
56 >>> Decimal("12.34") + Decimal("3.87") - Decimal("18.41")
57 Decimal("-2.20")
58 >>> dig = Decimal(1)
59 >>> print dig / Decimal(3)
60 0.333333333
61 >>> getcontext().prec = 18
62 >>> print dig / Decimal(3)
63 0.333333333333333333
64 >>> print dig.sqrt()
65 1
66 >>> print Decimal(3).sqrt()
67 1.73205080756887729
68 >>> print Decimal(3) ** 123
69 4.85192780976896427E+58
70 >>> inf = Decimal(1) / Decimal(0)
71 >>> print inf
72 Infinity
73 >>> neginf = Decimal(-1) / Decimal(0)
74 >>> print neginf
75 -Infinity
76 >>> print neginf + inf
77 NaN
78 >>> print neginf * inf
79 -Infinity
80 >>> print dig / 0
81 Infinity
82 >>> getcontext().traps[DivisionByZero] = 1
83 >>> print dig / 0
84 Traceback (most recent call last):
85   ...
86   ...
87   ...
88 DivisionByZero: x / 0
89 >>> c = Context()
90 >>> c.traps[InvalidOperation] = 0
91 >>> print c.flags[InvalidOperation]
92 0
93 >>> c.divide(Decimal(0), Decimal(0))
94 Decimal("NaN")
95 >>> c.traps[InvalidOperation] = 1
96 >>> print c.flags[InvalidOperation]
97 1
98 >>> c.flags[InvalidOperation] = 0
99 >>> print c.flags[InvalidOperation]
100 0
101 >>> print c.divide(Decimal(0), Decimal(0))
102 Traceback (most recent call last):
103   ...
104   ...
105   ...
106 InvalidOperation: 0 / 0
107 >>> print c.flags[InvalidOperation]
108 1
109 >>> c.flags[InvalidOperation] = 0
110 >>> c.traps[InvalidOperation] = 0
111 >>> print c.divide(Decimal(0), Decimal(0))
112 NaN
113 >>> print c.flags[InvalidOperation]
114 1
115 >>>
116 """
117
118 __all__ = [
119     # Two major classes
120     'Decimal', 'Context',
121
122     # Contexts
123     'DefaultContext', 'BasicContext', 'ExtendedContext',
124
125     # Exceptions
126     'DecimalException', 'Clamped', 'InvalidOperation', 'DivisionByZero',
127     'Inexact', 'Rounded', 'Subnormal', 'Overflow', 'Underflow',
128
129     # Constants for use in setting up contexts
130     'ROUND_DOWN', 'ROUND_HALF_UP', 'ROUND_HALF_EVEN', 'ROUND_CEILING',
131     'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN',
132
133     # Functions for manipulating contexts
134     'setcontext', 'getcontext'
135 ]
136
137 import copy as _copy
138
139 #Rounding
140 ROUND_DOWN = 'ROUND_DOWN'
141 ROUND_HALF_UP = 'ROUND_HALF_UP'
142 ROUND_HALF_EVEN = 'ROUND_HALF_EVEN'
143 ROUND_CEILING = 'ROUND_CEILING'
144 ROUND_FLOOR = 'ROUND_FLOOR'
145 ROUND_UP = 'ROUND_UP'
146 ROUND_HALF_DOWN = 'ROUND_HALF_DOWN'
147
148 #Rounding decision (not part of the public API)
149 NEVER_ROUND = 'NEVER_ROUND'    # Round in division (non-divmod), sqrt ONLY
150 ALWAYS_ROUND = 'ALWAYS_ROUND'  # Every operation rounds at end.
151
152 #Errors
153
154 class DecimalException(ArithmeticError):
155     """Base exception class.
156
157     Used exceptions derive from this.
158     If an exception derives from another exception besides this (such as
159     Underflow (Inexact, Rounded, Subnormal) that indicates that it is only
160     called if the others are present.  This isn't actually used for
161     anything, though.
162
163     handle  -- Called when context._raise_error is called and the
164                trap_enabler is set.  First argument is self, second is the
165                context.  More arguments can be given, those being after
166                the explanation in _raise_error (For example,
167                context._raise_error(NewError, '(-x)!', self._sign) would
168                call NewError().handle(context, self._sign).)
169
170     To define a new exception, it should be sufficient to have it derive
171     from DecimalException.
172     """
173     def handle(self, context, *args):
174         pass
175
176
177 class Clamped(DecimalException):
178     """Exponent of a 0 changed to fit bounds.
179
180     This occurs and signals clamped if the exponent of a result has been
181     altered in order to fit the constraints of a specific concrete
182     representation. This may occur when the exponent of a zero result would
183     be outside the bounds of a representation, or  when a large normal
184     number would have an encoded exponent that cannot be represented. In
185     this latter case, the exponent is reduced to fit and the corresponding
186     number of zero digits are appended to the coefficient ("fold-down").
187     """
188
189
190 class InvalidOperation(DecimalException):
191     """An invalid operation was performed.
192
193     Various bad things cause this:
194
195     Something creates a signaling NaN
196     -INF + INF
197      0 * (+-)INF
198      (+-)INF / (+-)INF
199     x % 0
200     (+-)INF % x
201     x._rescale( non-integer )
202     sqrt(-x) , x > 0
203     0 ** 0
204     x ** (non-integer)
205     x ** (+-)INF
206     An operand is invalid
207     """
208     def handle(self, context, *args):
209         if args:
210             if args[0] == 1: #sNaN, must drop 's' but keep diagnostics
211                 return Decimal( (args[1]._sign, args[1]._int, 'n') )
212         return NaN
213
214 class ConversionSyntax(InvalidOperation):
215     """Trying to convert badly formed string.
216
217     This occurs and signals invalid-operation if an string is being
218     converted to a number and it does not conform to the numeric string
219     syntax. The result is [0,qNaN].
220     """
221
222     def handle(self, context, *args):
223         return (0, (0,), 'n') #Passed to something which uses a tuple.
224
225 class DivisionByZero(DecimalException, ZeroDivisionError):
226     """Division by 0.
227
228     This occurs and signals division-by-zero if division of a finite number
229     by zero was attempted (during a divide-integer or divide operation, or a
230     power operation with negative right-hand operand), and the dividend was
231     not zero.
232
233     The result of the operation is [sign,inf], where sign is the exclusive
234     or of the signs of the operands for divide, or is 1 for an odd power of
235     -0, for power.
236     """
237
238     def handle(self, context, sign, double = None, *args):
239         if double is not None:
240             return (Infsign[sign],)*2
241         return Infsign[sign]
242
243 class DivisionImpossible(InvalidOperation):
244     """Cannot perform the division adequately.
245
246     This occurs and signals invalid-operation if the integer result of a
247     divide-integer or remainder operation had too many digits (would be
248     longer than precision). The result is [0,qNaN].
249     """
250
251     def handle(self, context, *args):
252         return (NaN, NaN)
253
254 class DivisionUndefined(InvalidOperation, ZeroDivisionError):
255     """Undefined result of division.
256
257     This occurs and signals invalid-operation if division by zero was
258     attempted (during a divide-integer, divide, or remainder operation), and
259     the dividend is also zero. The result is [0,qNaN].
260     """
261
262     def handle(self, context, tup=None, *args):
263         if tup is not None:
264             return (NaN, NaN) #for 0 %0, 0 // 0
265         return NaN
266
267 class Inexact(DecimalException):
268     """Had to round, losing information.
269
270     This occurs and signals inexact whenever the result of an operation is
271     not exact (that is, it needed to be rounded and any discarded digits
272     were non-zero), or if an overflow or underflow condition occurs. The
273     result in all cases is unchanged.
274
275     The inexact signal may be tested (or trapped) to determine if a given
276     operation (or sequence of operations) was inexact.
277     """
278     pass
279
280 class InvalidContext(InvalidOperation):
281     """Invalid context.  Unknown rounding, for example.
282
283     This occurs and signals invalid-operation if an invalid context was
284     detected during an operation. This can occur if contexts are not checked
285     on creation and either the precision exceeds the capability of the
286     underlying concrete representation or an unknown or unsupported rounding
287     was specified. These aspects of the context need only be checked when
288     the values are required to be used. The result is [0,qNaN].
289     """
290
291     def handle(self, context, *args):
292         return NaN
293
294 class Rounded(DecimalException):
295     """Number got rounded (not  necessarily changed during rounding).
296
297     This occurs and signals rounded whenever the result of an operation is
298     rounded (that is, some zero or non-zero digits were discarded from the
299     coefficient), or if an overflow or underflow condition occurs. The
300     result in all cases is unchanged.
301
302     The rounded signal may be tested (or trapped) to determine if a given
303     operation (or sequence of operations) caused a loss of precision.
304     """
305     pass
306
307 class Subnormal(DecimalException):
308     """Exponent < Emin before rounding.
309
310     This occurs and signals subnormal whenever the result of a conversion or
311     operation is subnormal (that is, its adjusted exponent is less than
312     Emin, before any rounding). The result in all cases is unchanged.
313
314     The subnormal signal may be tested (or trapped) to determine if a given
315     or operation (or sequence of operations) yielded a subnormal result.
316     """
317     pass
318
319 class Overflow(Inexact, Rounded):
320     """Numerical overflow.
321
322     This occurs and signals overflow if the adjusted exponent of a result
323     (from a conversion or from an operation that is not an attempt to divide
324     by zero), after rounding, would be greater than the largest value that
325     can be handled by the implementation (the value Emax).
326
327     The result depends on the rounding mode:
328
329     For round-half-up and round-half-even (and for round-half-down and
330     round-up, if implemented), the result of the operation is [sign,inf],
331     where sign is the sign of the intermediate result. For round-down, the
332     result is the largest finite number that can be represented in the
333     current precision, with the sign of the intermediate result. For
334     round-ceiling, the result is the same as for round-down if the sign of
335     the intermediate result is 1, or is [0,inf] otherwise. For round-floor,
336     the result is the same as for round-down if the sign of the intermediate
337     result is 0, or is [1,inf] otherwise. In all cases, Inexact and Rounded
338     will also be raised.
339    """
340
341     def handle(self, context, sign, *args):
342         if context.rounding in (ROUND_HALF_UP, ROUND_HALF_EVEN,
343                                      ROUND_HALF_DOWN, ROUND_UP):
344             return Infsign[sign]
345         if sign == 0:
346             if context.rounding == ROUND_CEILING:
347                 return Infsign[sign]
348             return Decimal((sign, (9,)*context.prec,
349                             context.Emax-context.prec+1))
350         if sign == 1:
351             if context.rounding == ROUND_FLOOR:
352                 return Infsign[sign]
353             return Decimal( (sign, (9,)*context.prec,
354                              context.Emax-context.prec+1))
355
356
357 class Underflow(Inexact, Rounded, Subnormal):
358     """Numerical underflow with result rounded to 0.
359
360     This occurs and signals underflow if a result is inexact and the
361     adjusted exponent of the result would be smaller (more negative) than
362     the smallest value that can be handled by the implementation (the value
363     Emin). That is, the result is both inexact and subnormal.
364
365     The result after an underflow will be a subnormal number rounded, if
366     necessary, so that its exponent is not less than Etiny. This may result
367     in 0 with the sign of the intermediate result and an exponent of Etiny.
368
369     In all cases, Inexact, Rounded, and Subnormal will also be raised.
370     """
371
372 # List of public traps and flags
373 _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
374            Underflow, InvalidOperation, Subnormal]
375
376 # Map conditions (per the spec) to signals
377 _condition_map = {ConversionSyntax:InvalidOperation,
378                   DivisionImpossible:InvalidOperation,
379                   DivisionUndefined:InvalidOperation,
380                   InvalidContext:InvalidOperation}
381
382 ##### Context Functions #######################################
383
384 # The getcontext() and setcontext() function manage access to a thread-local
385 # current context.  Py2.4 offers direct support for thread locals.  If that
386 # is not available, use threading.currentThread() which is slower but will
387 # work for older Pythons.  If threads are not part of the build, create a
388 # mock threading object with threading.local() returning the module namespace.
389
390 try:
391     import threading
392 except ImportError:
393     # Python was compiled without threads; create a mock object instead
394     import sys
395     class MockThreading:
396         def local(self, sys=sys):
397             return sys.modules[__name__]
398     threading = MockThreading()
399     del sys, MockThreading
400
401 try:
402     threading.local
403
404 except AttributeError:
405
406     #To fix reloading, force it to create a new context
407     #Old contexts have different exceptions in their dicts, making problems.
408     if hasattr(threading.currentThread(), '__decimal_context__'):
409         del threading.currentThread().__decimal_context__
410
411     def setcontext(context):
412         """Set this thread's context to context."""
413         if context in (DefaultContext, BasicContext, ExtendedContext):
414             context = context.copy()
415             context.clear_flags()
416         threading.currentThread().__decimal_context__ = context
417
418     def getcontext():
419         """Returns this thread's context.
420
421         If this thread does not yet have a context, returns
422         a new context and sets this thread's context.
423         New contexts are copies of DefaultContext.
424         """
425         try:
426             return threading.currentThread().__decimal_context__
427         except AttributeError:
428             context = Context()
429             threading.currentThread().__decimal_context__ = context
430             return context
431
432 else:
433
434     local = threading.local()
435     if hasattr(local, '__decimal_context__'):
436         del local.__decimal_context__
437
438     def getcontext(_local=local):
439         """Returns this thread's context.
440
441         If this thread does not yet have a context, returns
442         a new context and sets this thread's context.
443         New contexts are copies of DefaultContext.
444         """
445         try:
446             return _local.__decimal_context__
447         except AttributeError:
448             context = Context()
449             _local.__decimal_context__ = context
450             return context
451
452     def setcontext(context, _local=local):
453         """Set this thread's context to context."""
454         if context in (DefaultContext, BasicContext, ExtendedContext):
455             context = context.copy()
456             context.clear_flags()
457         _local.__decimal_context__ = context
458
459     del threading, local        # Don't contaminate the namespace
460
461
462 ##### Decimal class ###########################################
463
464 class Decimal(object):
465     """Floating point class for decimal arithmetic."""
466
467     __slots__ = ('_exp','_int','_sign', '_is_special')
468     # Generally, the value of the Decimal instance is given by
469     #  (-1)**_sign * _int * 10**_exp
470     # Special values are signified by _is_special == True
471
472     # We're immutable, so use __new__ not __init__
473     def __new__(cls, value="0", context=None):
474         """Create a decimal point instance.
475
476         >>> Decimal('3.14')              # string input
477         Decimal("3.14")
478         >>> Decimal((0, (3, 1, 4), -2))  # tuple input (sign, digit_tuple, exponent)
479         Decimal("3.14")
480         >>> Decimal(314)                 # int or long
481         Decimal("314")
482         >>> Decimal(Decimal(314))        # another decimal instance
483         Decimal("314")
484         """
485
486         self = object.__new__(cls)
487         self._is_special = False
488
489         # From an internal working value
490         if isinstance(value, _WorkRep):
491             self._sign = value.sign
492             self._int = tuple(map(int, str(value.int)))
493             self._exp = int(value.exp)
494             return self
495
496         # From another decimal
497         if isinstance(value, Decimal):
498             self._exp  = value._exp
499             self._sign = value._sign
500             self._int  = value._int
501             self._is_special  = value._is_special
502             return self
503
504         # From an integer
505         if isinstance(value, (int,long)):
506             if value >= 0:
507                 self._sign = 0
508             else:
509                 self._sign = 1
510             self._exp = 0
511             self._int = tuple(map(int, str(abs(value))))
512             return self
513
514         # tuple/list conversion (possibly from as_tuple())
515         if isinstance(value, (list,tuple)):
516             if len(value) != 3:
517                 raise ValueError, 'Invalid arguments'
518             if value[0] not in (0,1):
519                 raise ValueError, 'Invalid sign'
520             for digit in value[1]:
521                 if not isinstance(digit, (int,long)) or digit < 0:
522                     raise ValueError, "The second value in the tuple must be composed of non negative integer elements."
523
524             self._sign = value[0]
525             self._int  = tuple(value[1])
526             if value[2] in ('F','n','N'):
527                 self._exp = value[2]
528                 self._is_special = True
529             else:
530                 self._exp  = int(value[2])
531             return self
532
533         if isinstance(value, float):
534             raise TypeError("Cannot convert float to Decimal.  " +
535                             "First convert the float to a string")
536
537         # Other argument types may require the context during interpretation
538         if context is None:
539             context = getcontext()
540
541         # From a string
542         # REs insist on real strings, so we can too.
543         if isinstance(value, basestring):
544             if _isinfinity(value):
545                 self._exp = 'F'
546                 self._int = (0,)
547                 self._is_special = True
548                 if _isinfinity(value) == 1:
549                     self._sign = 0
550                 else:
551                     self._sign = 1
552                 return self
553             if _isnan(value):
554                 sig, sign, diag = _isnan(value)
555                 self._is_special = True
556                 if len(diag) > context.prec: #Diagnostic info too long
557                     self._sign, self._int, self._exp = \
558                                 context._raise_error(ConversionSyntax)
559                     return self
560                 if sig == 1:
561                     self._exp = 'n' #qNaN
562                 else: #sig == 2
563                     self._exp = 'N' #sNaN
564                 self._sign = sign
565                 self._int = tuple(map(int, diag)) #Diagnostic info
566                 return self
567             try:
568                 self._sign, self._int, self._exp = _string2exact(value)
569             except ValueError:
570                 self._is_special = True
571                 self._sign, self._int, self._exp = context._raise_error(ConversionSyntax)
572             return self
573
574         raise TypeError("Cannot convert %r to Decimal" % value)
575
576     def _isnan(self):
577         """Returns whether the number is not actually one.
578
579         0 if a number
580         1 if NaN
581         2 if sNaN
582         """
583         if self._is_special:
584             exp = self._exp
585             if exp == 'n':
586                 return 1
587             elif exp == 'N':
588                 return 2
589         return 0
590
591     def _isinfinity(self):
592         """Returns whether the number is infinite
593
594         0 if finite or not a number
595         1 if +INF
596         -1 if -INF
597         """
598         if self._exp == 'F':
599             if self._sign:
600                 return -1
601             return 1
602         return 0
603
604     def _check_nans(self, other = None, context=None):
605         """Returns whether the number is not actually one.
606
607         if self, other are sNaN, signal
608         if self, other are NaN return nan
609         return 0
610
611         Done before operations.
612         """
613
614         self_is_nan = self._isnan()
615         if other is None:
616             other_is_nan = False
617         else:
618             other_is_nan = other._isnan()
619
620         if self_is_nan or other_is_nan:
621             if context is None:
622                 context = getcontext()
623
624             if self_is_nan == 2:
625                 return context._raise_error(InvalidOperation, 'sNaN',
626                                         1, self)
627             if other_is_nan == 2:
628                 return context._raise_error(InvalidOperation, 'sNaN',
629                                         1, other)
630             if self_is_nan:
631                 return self
632
633             return other
634         return 0
635
636     def __nonzero__(self):
637         """Is the number non-zero?
638
639         0 if self == 0
640         1 if self != 0
641         """
642         if self._is_special:
643             return 1
644         return sum(self._int) != 0
645
646     def __cmp__(self, other, context=None):
647         other = _convert_other(other)
648         if other is NotImplemented:
649             return other
650
651         if self._is_special or other._is_special:
652             ans = self._check_nans(other, context)
653             if ans:
654                 return 1 # Comparison involving NaN's always reports self > other
655
656             # INF = INF
657             return cmp(self._isinfinity(), other._isinfinity())
658
659         if not self and not other:
660             return 0 #If both 0, sign comparison isn't certain.
661
662         #If different signs, neg one is less
663         if other._sign < self._sign:
664             return -1
665         if self._sign < other._sign:
666             return 1
667
668         self_adjusted = self.adjusted()
669         other_adjusted = other.adjusted()
670         if self_adjusted == other_adjusted and \
671            self._int + (0,)*(self._exp - other._exp) == \
672            other._int + (0,)*(other._exp - self._exp):
673             return 0 #equal, except in precision. ([0]*(-x) = [])
674         elif self_adjusted > other_adjusted and self._int[0] != 0:
675             return (-1)**self._sign
676         elif self_adjusted < other_adjusted and other._int[0] != 0:
677             return -((-1)**self._sign)
678
679         # Need to round, so make sure we have a valid context
680         if context is None:
681             context = getcontext()
682
683         context = context._shallow_copy()
684         rounding = context._set_rounding(ROUND_UP)