Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(70189)

Side by Side Diff: Lib/decimal.py

Issue 7652: Merge C version of decimal into py3k.
Patch Set: Created 8 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright (c) 2004 Python Software Foundation. 1 # Copyright (c) 2004 Python Software Foundation.
2 # All rights reserved. 2 # All rights reserved.
3 3
4 # Written by Eric Price <eprice at tjhsst.edu> 4 # Written by Eric Price <eprice at tjhsst.edu>
5 # and Facundo Batista <facundo at taniquetil.com.ar> 5 # and Facundo Batista <facundo at taniquetil.com.ar>
6 # and Raymond Hettinger <python at rcn.com> 6 # and Raymond Hettinger <python at rcn.com>
7 # and Aahz <aahz at pobox.com> 7 # and Aahz <aahz at pobox.com>
8 # and Tim Peters 8 # and Tim Peters
9 9
10 # This module should be kept in sync with the latest updates of the 10 # This module should be kept in sync with the latest updates of the
(...skipping 28 matching lines...) Expand all
39 >>> from decimal import * 39 >>> from decimal import *
40 >>> setcontext(ExtendedContext) 40 >>> setcontext(ExtendedContext)
41 >>> Decimal(0) 41 >>> Decimal(0)
42 Decimal('0') 42 Decimal('0')
43 >>> Decimal('1') 43 >>> Decimal('1')
44 Decimal('1') 44 Decimal('1')
45 >>> Decimal('-.0123') 45 >>> Decimal('-.0123')
46 Decimal('-0.0123') 46 Decimal('-0.0123')
47 >>> Decimal(123456) 47 >>> Decimal(123456)
48 Decimal('123456') 48 Decimal('123456')
49 >>> Decimal('123.45e12345678901234567890') 49 >>> Decimal('123.45e12345678')
50 Decimal('1.2345E+12345678901234567892') 50 Decimal('1.2345E+12345680')
51 >>> Decimal('1.33') + Decimal('1.27') 51 >>> Decimal('1.33') + Decimal('1.27')
52 Decimal('2.60') 52 Decimal('2.60')
53 >>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41') 53 >>> Decimal('12.34') + Decimal('3.87') - Decimal('18.41')
54 Decimal('-2.20') 54 Decimal('-2.20')
55 >>> dig = Decimal(1) 55 >>> dig = Decimal(1)
56 >>> print(dig / Decimal(3)) 56 >>> print(dig / Decimal(3))
57 0.333333333 57 0.333333333
58 >>> getcontext().prec = 18 58 >>> getcontext().prec = 18
59 >>> print(dig / Decimal(3)) 59 >>> print(dig / Decimal(3))
60 0.333333333333333333 60 0.333333333333333333
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 372
373 # List of public traps and flags 373 # List of public traps and flags
374 _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded, 374 _signals = [Clamped, DivisionByZero, Inexact, Overflow, Rounded,
375 Underflow, InvalidOperation, Subnormal] 375 Underflow, InvalidOperation, Subnormal]
376 376
377 # Map conditions (per the spec) to signals 377 # Map conditions (per the spec) to signals
378 _condition_map = {ConversionSyntax:InvalidOperation, 378 _condition_map = {ConversionSyntax:InvalidOperation,
379 DivisionImpossible:InvalidOperation, 379 DivisionImpossible:InvalidOperation,
380 DivisionUndefined:InvalidOperation, 380 DivisionUndefined:InvalidOperation,
381 InvalidContext:InvalidOperation} 381 InvalidContext:InvalidOperation}
382
383 # Valid rounding modes
384 _rounding_modes = (ROUND_DOWN, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_CEILING,
385 ROUND_FLOOR, ROUND_UP, ROUND_HALF_DOWN, ROUND_05UP)
382 386
383 ##### Context Functions ################################################## 387 ##### Context Functions ##################################################
384 388
385 # The getcontext() and setcontext() function manage access to a thread-local 389 # The getcontext() and setcontext() function manage access to a thread-local
386 # current context. Py2.4 offers direct support for thread locals. If that 390 # current context. Py2.4 offers direct support for thread locals. If that
387 # is not available, use threading.current_thread() which is slower but will 391 # is not available, use threading.current_thread() which is slower but will
388 # work for older Pythons. If threads are not part of the build, create a 392 # work for older Pythons. If threads are not part of the build, create a
389 # mock threading object with threading.local() returning the module namespace. 393 # mock threading object with threading.local() returning the module namespace.
390 394
391 try: 395 try:
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
677 >>> Decimal.from_float(float('inf')) 681 >>> Decimal.from_float(float('inf'))
678 Decimal('Infinity') 682 Decimal('Infinity')
679 >>> Decimal.from_float(-float('inf')) 683 >>> Decimal.from_float(-float('inf'))
680 Decimal('-Infinity') 684 Decimal('-Infinity')
681 >>> Decimal.from_float(-0.0) 685 >>> Decimal.from_float(-0.0)
682 Decimal('-0') 686 Decimal('-0')
683 687
684 """ 688 """
685 if isinstance(f, int): # handle integer inputs 689 if isinstance(f, int): # handle integer inputs
686 return cls(f) 690 return cls(f)
687 if _math.isinf(f) or _math.isnan(f): # raises TypeError if not a float 691 if not isinstance(f, float):
692 raise TypeError("argument must be int or float.")
693 if _math.isinf(f) or _math.isnan(f):
688 return cls(repr(f)) 694 return cls(repr(f))
689 if _math.copysign(1.0, f) == 1.0: 695 if _math.copysign(1.0, f) == 1.0:
690 sign = 0 696 sign = 0
691 else: 697 else:
692 sign = 1 698 sign = 1
693 n, d = abs(f).as_integer_ratio() 699 n, d = abs(f).as_integer_ratio()
694 k = d.bit_length() - 1 700 k = d.bit_length() - 1
695 result = _dec_from_triple(sign, str(n*5**k), -k) 701 result = _dec_from_triple(sign, str(n*5**k), -k)
696 if cls is Decimal: 702 if cls is Decimal:
697 return result 703 return result
(...skipping 3127 matching lines...) Expand 10 before | Expand all | Expand 10 after
3825 flags - When an exception is caused, flags[exception] is set. 3831 flags - When an exception is caused, flags[exception] is set.
3826 (Whether or not the trap_enabler is set) 3832 (Whether or not the trap_enabler is set)
3827 Should be reset by user of Decimal instance. 3833 Should be reset by user of Decimal instance.
3828 Emin - Minimum exponent 3834 Emin - Minimum exponent
3829 Emax - Maximum exponent 3835 Emax - Maximum exponent
3830 capitals - If 1, 1*10^1 is printed as 1E+1. 3836 capitals - If 1, 1*10^1 is printed as 1E+1.
3831 If 0, printed as 1e1 3837 If 0, printed as 1e1
3832 clamp - If 1, change exponents if too high (Default 0) 3838 clamp - If 1, change exponents if too high (Default 0)
3833 """ 3839 """
3834 3840
3835 def __init__(self, prec=None, rounding=None, 3841 def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
3836 traps=None, flags=None, 3842 capitals=None, clamp=None, flags=None, traps=None,
3837 Emin=None, Emax=None, 3843 _ignored_flags=None):
3838 capitals=None, clamp=None,
3839 _ignored_flags=None):
3840 # Set defaults; for everything except flags and _ignored_flags, 3844 # Set defaults; for everything except flags and _ignored_flags,
3841 # inherit from DefaultContext. 3845 # inherit from DefaultContext.
3842 try: 3846 try:
3843 dc = DefaultContext 3847 dc = DefaultContext
3844 except NameError: 3848 except NameError:
3845 pass 3849 pass
3846 3850
3847 self.prec = prec if prec is not None else dc.prec 3851 self.prec = prec if prec is not None else dc.prec
3848 self.rounding = rounding if rounding is not None else dc.rounding 3852 self.rounding = rounding if rounding is not None else dc.rounding
3849 self.Emin = Emin if Emin is not None else dc.Emin 3853 self.Emin = Emin if Emin is not None else dc.Emin
3850 self.Emax = Emax if Emax is not None else dc.Emax 3854 self.Emax = Emax if Emax is not None else dc.Emax
3851 self.capitals = capitals if capitals is not None else dc.capitals 3855 self.capitals = capitals if capitals is not None else dc.capitals
3852 self.clamp = clamp if clamp is not None else dc.clamp 3856 self.clamp = clamp if clamp is not None else dc.clamp
3853 3857
3854 if _ignored_flags is None: 3858 if _ignored_flags is None:
3855 self._ignored_flags = [] 3859 self._ignored_flags = []
3856 else: 3860 else:
3857 self._ignored_flags = _ignored_flags 3861 self._ignored_flags = _ignored_flags
3858 3862
3859 if traps is None: 3863 if traps is None:
3860 self.traps = dc.traps.copy() 3864 self.traps = dc.traps.copy()
3861 elif not isinstance(traps, dict): 3865 elif not isinstance(traps, dict):
3862 self.traps = dict((s, int(s in traps)) for s in _signals) 3866 self.traps = dict((s, int(s in traps)) for s in _signals + traps)
3863 else: 3867 else:
3864 self.traps = traps 3868 self.traps = traps
3865 3869
3866 if flags is None: 3870 if flags is None:
3867 self.flags = dict.fromkeys(_signals, 0) 3871 self.flags = dict.fromkeys(_signals, 0)
3868 elif not isinstance(flags, dict): 3872 elif not isinstance(flags, dict):
3869 self.flags = dict((s, int(s in flags)) for s in _signals) 3873 self.flags = dict((s, int(s in flags)) for s in _signals + flags)
3870 else: 3874 else:
3871 self.flags = flags 3875 self.flags = flags
3876
3877 def _set_integer_check(self, name, value, vmin, vmax):
3878 if not isinstance(value, int):
3879 raise TypeError("%s must be an integer" % name)
3880 if vmin == '-inf':
3881 if value > vmax:
3882 raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin , vmax, value))
3883 elif vmax == 'inf':
3884 if value < vmin:
3885 raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin , vmax, value))
3886 else:
3887 if value < vmin or value > vmax:
3888 raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value))
3889 return object.__setattr__(self, name, value)
3890
3891 def _set_signal_dict(self, name, d):
3892 if not isinstance(d, dict):
3893 raise TypeError("%s must be a signal dict" % d)
3894 for key in d:
3895 if not key in _signals:
3896 raise TypeError("%s is not a valid signal dict" % d)
3897 for key in _signals:
3898 if not key in d:
3899 raise TypeError("%s is not a valid signal dict" % d)
3900 return object.__setattr__(self, name, d)
3901
3902 def __setattr__(self, name, value):
3903 if name == 'prec':
3904 return self._set_integer_check(name, value, 1, 'inf')
3905 elif name == 'Emin':
3906 return self._set_integer_check(name, value, '-inf', 0)
3907 elif name == 'Emax':
3908 return self._set_integer_check(name, value, 0, 'inf')
3909 elif name == 'capitals':
3910 return self._set_integer_check(name, value, 0, 1)
3911 elif name == 'clamp':
3912 return self._set_integer_check(name, value, 0, 1)
3913 elif name == 'rounding':
3914 if not value in _rounding_modes:
3915 # raise TypeError even for strings to have consistency
3916 # among various implementations.
3917 raise TypeError("%s: invalid rounding mode" % value)
3918 return object.__setattr__(self, name, value)
3919 elif name == 'flags' or name == 'traps':
3920 return self._set_signal_dict(name, value)
3921 elif name == '_ignored_flags':
3922 return object.__setattr__(self, name, value)
3923 else:
3924 raise AttributeError(
3925 "'decimal.Context' object has no attribute '%s'" % name)
3926
3927 def __delattr__(self, name):
3928 raise AttributeError("%s cannot be deleted" % name)
3929
3930 # Support for pickling, copy, and deepcopy
3931 def __reduce__(self):
3932 flags = [sig for sig, v in self.flags.items() if v]
3933 traps = [sig for sig, v in self.traps.items() if v]
3934 return (self.__class__,
3935 (self.prec, self.rounding, self.Emin, self.Emax,
3936 self.capitals, self.clamp, flags, traps))
3872 3937
3873 def __repr__(self): 3938 def __repr__(self):
3874 """Show the current context.""" 3939 """Show the current context."""
3875 s = [] 3940 s = []
3876 s.append('Context(prec=%(prec)d, rounding=%(rounding)s, ' 3941 s.append('Context(prec=%(prec)d, rounding=%(rounding)s, '
3877 'Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d, ' 3942 'Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d, '
3878 'clamp=%(clamp)d' 3943 'clamp=%(clamp)d'
3879 % vars(self)) 3944 % vars(self))
3880 names = [f.__name__ for f, v in self.flags.items() if v] 3945 names = [f.__name__ for f, v in self.flags.items() if v]
3881 s.append('flags=[' + ', '.join(names) + ']') 3946 s.append('flags=[' + ', '.join(names) + ']')
3882 names = [t.__name__ for t, v in self.traps.items() if v] 3947 names = [t.__name__ for t, v in self.traps.items() if v]
3883 s.append('traps=[' + ', '.join(names) + ']') 3948 s.append('traps=[' + ', '.join(names) + ']')
3884 return ', '.join(s) + ')' 3949 return ', '.join(s) + ')'
3885 3950
3886 def clear_flags(self): 3951 def clear_flags(self):
3887 """Reset all flags to zero""" 3952 """Reset all flags to zero"""
3888 for flag in self.flags: 3953 for flag in self.flags:
3889 self.flags[flag] = 0 3954 self.flags[flag] = 0
3890 3955
3891 def _shallow_copy(self): 3956 def _shallow_copy(self):
3892 """Returns a shallow copy from self.""" 3957 """Returns a shallow copy from self."""
3893 nc = Context(self.prec, self.rounding, self.traps, 3958 nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
3894 self.flags, self.Emin, self.Emax, 3959 self.capitals, self.clamp, self.flags, self.traps,
3895 self.capitals, self.clamp, self._ignored_flags) 3960 self._ignored_flags)
3896 return nc 3961 return nc
3897 3962
3898 def copy(self): 3963 def copy(self):
3899 """Returns a deep copy from self.""" 3964 """Returns a deep copy from self."""
3900 nc = Context(self.prec, self.rounding, self.traps.copy(), 3965 nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
3901 self.flags.copy(), self.Emin, self.Emax, 3966 self.capitals, self.clamp,
3902 self.capitals, self.clamp, self._ignored_flags) 3967 self.flags.copy(), self.traps.copy(),
3968 self._ignored_flags)
3903 return nc 3969 return nc
3904 __copy__ = copy 3970 __copy__ = copy
3905
3906 # _clamp is provided for backwards compatibility with third-party
3907 # code. May be removed in Python >= 3.3.
3908 def _get_clamp(self):
3909 "_clamp mirrors the clamp attribute. Its use is deprecated."
3910 import warnings
3911 warnings.warn('Use of the _clamp attribute is deprecated. '
3912 'Please use clamp instead.',
3913 DeprecationWarning)
3914 return self.clamp
3915
3916 def _set_clamp(self, clamp):
3917 "_clamp mirrors the clamp attribute. Its use is deprecated."
3918 import warnings
3919 warnings.warn('Use of the _clamp attribute is deprecated. '
3920 'Please use clamp instead.',
3921 DeprecationWarning)
3922 self.clamp = clamp
3923
3924 # don't bother with _del_clamp; no sane 3rd party code should
3925 # be deleting the _clamp attribute
3926 _clamp = property(_get_clamp, _set_clamp)
3927 3971
3928 def _raise_error(self, condition, explanation = None, *args): 3972 def _raise_error(self, condition, explanation = None, *args):
3929 """Handles an error 3973 """Handles an error
3930 3974
3931 If the flag is in _ignored_flags, returns the default response. 3975 If the flag is in _ignored_flags, returns the default response.
3932 Otherwise, it sets the flag, then, if the corresponding 3976 Otherwise, it sets the flag, then, if the corresponding
3933 trap_enabler is set, it reraises the exception. Otherwise, it returns 3977 trap_enabler is set, it reraises the exception. Otherwise, it returns
3934 the default value after setting the flag. 3978 the default value after setting the flag.
3935 """ 3979 """
3936 error = _condition_map.get(condition, condition) 3980 error = _condition_map.get(condition, condition)
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
4077 4121
4078 def canonical(self, a): 4122 def canonical(self, a):
4079 """Returns the same Decimal object. 4123 """Returns the same Decimal object.
4080 4124
4081 As we do not have different encodings for the same number, the 4125 As we do not have different encodings for the same number, the
4082 received object already is in its canonical form. 4126 received object already is in its canonical form.
4083 4127
4084 >>> ExtendedContext.canonical(Decimal('2.50')) 4128 >>> ExtendedContext.canonical(Decimal('2.50'))
4085 Decimal('2.50') 4129 Decimal('2.50')
4086 """ 4130 """
4131 if not isinstance(a, Decimal):
4132 raise TypeError("canonical requires a Decimal as an argument.")
4087 return a.canonical(context=self) 4133 return a.canonical(context=self)
4088 4134
4089 def compare(self, a, b): 4135 def compare(self, a, b):
4090 """Compares values numerically. 4136 """Compares values numerically.
4091 4137
4092 If the signs of the operands differ, a value representing each operand 4138 If the signs of the operands differ, a value representing each operand
4093 ('-1' if the operand is less than zero, '0' if the operand is zero or 4139 ('-1' if the operand is less than zero, '0' if the operand is zero or
4094 negative zero, or '1' if the operand is greater than zero) is used in 4140 negative zero, or '1' if the operand is greater than zero) is used in
4095 place of that operand for the comparison instead of the actual 4141 place of that operand for the comparison instead of the actual
4096 operand. 4142 operand.
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
4387 4433
4388 def is_canonical(self, a): 4434 def is_canonical(self, a):
4389 """Return True if the operand is canonical; otherwise return False. 4435 """Return True if the operand is canonical; otherwise return False.
4390 4436
4391 Currently, the encoding of a Decimal instance is always 4437 Currently, the encoding of a Decimal instance is always
4392 canonical, so this method returns True for any Decimal. 4438 canonical, so this method returns True for any Decimal.
4393 4439
4394 >>> ExtendedContext.is_canonical(Decimal('2.50')) 4440 >>> ExtendedContext.is_canonical(Decimal('2.50'))
4395 True 4441 True
4396 """ 4442 """
4443 if not isinstance(a, Decimal):
4444 raise TypeError("is_canonical requires a Decimal as an argument.")
4397 return a.is_canonical() 4445 return a.is_canonical()
4398 4446
4399 def is_finite(self, a): 4447 def is_finite(self, a):
4400 """Return True if the operand is finite; otherwise return False. 4448 """Return True if the operand is finite; otherwise return False.
4401 4449
4402 A Decimal instance is considered finite if it is neither 4450 A Decimal instance is considered finite if it is neither
4403 infinite nor a NaN. 4451 infinite nor a NaN.
4404 4452
4405 >>> ExtendedContext.is_finite(Decimal('2.50')) 4453 >>> ExtendedContext.is_finite(Decimal('2.50'))
4406 True 4454 True
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after
4979 -NaN 5027 -NaN
4980 -Infinity 5028 -Infinity
4981 -Normal 5029 -Normal
4982 -Subnormal 5030 -Subnormal
4983 -Zero 5031 -Zero
4984 +Zero 5032 +Zero
4985 +Subnormal 5033 +Subnormal
4986 +Normal 5034 +Normal
4987 +Infinity 5035 +Infinity
4988 5036
4989 >>> c = Context(ExtendedContext) 5037 >>> c = ExtendedContext.copy()
4990 >>> c.Emin = -999 5038 >>> c.Emin = -999
4991 >>> c.Emax = 999 5039 >>> c.Emax = 999
4992 >>> c.number_class(Decimal('Infinity')) 5040 >>> c.number_class(Decimal('Infinity'))
4993 '+Infinity' 5041 '+Infinity'
4994 >>> c.number_class(Decimal('1E-10')) 5042 >>> c.number_class(Decimal('1E-10'))
4995 '+Normal' 5043 '+Normal'
4996 >>> c.number_class(Decimal('2.50')) 5044 >>> c.number_class(Decimal('2.50'))
4997 '+Normal' 5045 '+Normal'
4998 >>> c.number_class(Decimal('0.1E-999')) 5046 >>> c.number_class(Decimal('0.1E-999'))
4999 '+Subnormal' 5047 '+Subnormal'
(...skipping 1274 matching lines...) Expand 10 before | Expand all | Expand 10 after
6274 # _SignedInfinity[sign] is infinity w/ that sign 6322 # _SignedInfinity[sign] is infinity w/ that sign
6275 _SignedInfinity = (_Infinity, _NegativeInfinity) 6323 _SignedInfinity = (_Infinity, _NegativeInfinity)
6276 6324
6277 # Constants related to the hash implementation; hash(x) is based 6325 # Constants related to the hash implementation; hash(x) is based
6278 # on the reduction of x modulo _PyHASH_MODULUS 6326 # on the reduction of x modulo _PyHASH_MODULUS
6279 import sys 6327 import sys
6280 _PyHASH_MODULUS = sys.hash_info.modulus 6328 _PyHASH_MODULUS = sys.hash_info.modulus
6281 # hash values to use for positive and negative infinities, and nans 6329 # hash values to use for positive and negative infinities, and nans
6282 _PyHASH_INF = sys.hash_info.inf 6330 _PyHASH_INF = sys.hash_info.inf
6283 _PyHASH_NAN = sys.hash_info.nan 6331 _PyHASH_NAN = sys.hash_info.nan
6284 del sys
6285 6332
6286 # _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS 6333 # _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
6287 _PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) 6334 _PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
6288 6335
6336 if not '_decimal' in sys.modules:
6337 try:
6338 import _decimal
6339 s1 = set(dir())
6340 s2 = set(dir(_decimal))
6341 for name in s1 - s2:
6342 del globals()[name]
6343 del s1, s2, name
6344 from _decimal import *
6345 except:
amaury.forgeotdarc 2011/12/01 00:12:04 Is it possible to only catch ImportError, and only
skrah 2011/12/02 01:27:38 Yes, indeed.
skrah 2011/12/04 16:09:40 Done in http://hg.python.org/features/cdecimal/rev
6346 del sys
6289 6347
6290 if __name__ == '__main__': 6348 if __name__ == '__main__':
6291 import doctest, decimal 6349 import doctest, decimal
6292 doctest.testmod(decimal) 6350 doctest.testmod(decimal)
OLDNEW
« no previous file with comments | « Include/longintrepr.h ('k') | Lib/test/support.py » ('j') | Modules/_decimal/_decimal.c » ('J')

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+