Skip to content

Commit bb0a201

Browse files
authored
Merge pull request #6901 from ShaharNaveh/update-decimal
Update `decimal` from 3.14.2
2 parents 568f24c + 6af0af2 commit bb0a201

3 files changed

Lines changed: 206 additions & 99 deletions

File tree

Lib/_pydecimal.py

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
'ROUND_FLOOR', 'ROUND_UP', 'ROUND_HALF_DOWN', 'ROUND_05UP',
3939

4040
# Functions for manipulating contexts
41-
'setcontext', 'getcontext', 'localcontext',
41+
'setcontext', 'getcontext', 'localcontext', 'IEEEContext',
4242

4343
# Limits for the C version for compatibility
44-
'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY',
44+
'MAX_PREC', 'MAX_EMAX', 'MIN_EMIN', 'MIN_ETINY', 'IEEE_CONTEXT_MAX_BITS',
4545

4646
# C version: compile time choice that enables the thread local context (deprecated, now always true)
4747
'HAVE_THREADS',
@@ -83,10 +83,12 @@
8383
MAX_PREC = 999999999999999999
8484
MAX_EMAX = 999999999999999999
8585
MIN_EMIN = -999999999999999999
86+
IEEE_CONTEXT_MAX_BITS = 512
8687
else:
8788
MAX_PREC = 425000000
8889
MAX_EMAX = 425000000
8990
MIN_EMIN = -425000000
91+
IEEE_CONTEXT_MAX_BITS = 256
9092

9193
MIN_ETINY = MIN_EMIN - (MAX_PREC-1)
9294

@@ -417,6 +419,27 @@ def sin(x):
417419
return ctx_manager
418420

419421

422+
def IEEEContext(bits, /):
423+
"""
424+
Return a context object initialized to the proper values for one of the
425+
IEEE interchange formats. The argument must be a multiple of 32 and less
426+
than IEEE_CONTEXT_MAX_BITS.
427+
"""
428+
if bits <= 0 or bits > IEEE_CONTEXT_MAX_BITS or bits % 32:
429+
raise ValueError("argument must be a multiple of 32, "
430+
f"with a maximum of {IEEE_CONTEXT_MAX_BITS}")
431+
432+
ctx = Context()
433+
ctx.prec = 9 * (bits//32) - 2
434+
ctx.Emax = 3 * (1 << (bits//16 + 3))
435+
ctx.Emin = 1 - ctx.Emax
436+
ctx.rounding = ROUND_HALF_EVEN
437+
ctx.clamp = 1
438+
ctx.traps = dict.fromkeys(_signals, False)
439+
440+
return ctx
441+
442+
420443
##### Decimal class #######################################################
421444

422445
# Do not subclass Decimal from numbers.Real and do not register it as such
@@ -582,6 +605,21 @@ def __new__(cls, value="0", context=None):
582605

583606
raise TypeError("Cannot convert %r to Decimal" % value)
584607

608+
@classmethod
609+
def from_number(cls, number):
610+
"""Converts a real number to a decimal number, exactly.
611+
612+
>>> Decimal.from_number(314) # int
613+
Decimal('314')
614+
>>> Decimal.from_number(0.1) # float
615+
Decimal('0.1000000000000000055511151231257827021181583404541015625')
616+
>>> Decimal.from_number(Decimal('3.14')) # another decimal instance
617+
Decimal('3.14')
618+
"""
619+
if isinstance(number, (int, Decimal, float)):
620+
return cls(number)
621+
raise TypeError("Cannot convert %r to Decimal" % number)
622+
585623
@classmethod
586624
def from_float(cls, f):
587625
"""Converts a float to a decimal number, exactly.
@@ -2425,12 +2463,12 @@ def __pow__(self, other, modulo=None, context=None):
24252463

24262464
return ans
24272465

2428-
def __rpow__(self, other, context=None):
2466+
def __rpow__(self, other, modulo=None, context=None):
24292467
"""Swaps self/other and returns __pow__."""
24302468
other = _convert_other(other)
24312469
if other is NotImplemented:
24322470
return other
2433-
return other.__pow__(self, context=context)
2471+
return other.__pow__(self, modulo, context=context)
24342472

24352473
def normalize(self, context=None):
24362474
"""Normalize- strip trailing 0s, change anything equal to 0 to 0e0"""
@@ -3302,7 +3340,10 @@ def _fill_logical(self, context, opa, opb):
33023340
return opa, opb
33033341

33043342
def logical_and(self, other, context=None):
3305-
"""Applies an 'and' operation between self and other's digits."""
3343+
"""Applies an 'and' operation between self and other's digits.
3344+
3345+
Both self and other must be logical numbers.
3346+
"""
33063347
if context is None:
33073348
context = getcontext()
33083349

@@ -3319,14 +3360,20 @@ def logical_and(self, other, context=None):
33193360
return _dec_from_triple(0, result.lstrip('0') or '0', 0)
33203361

33213362
def logical_invert(self, context=None):
3322-
"""Invert all its digits."""
3363+
"""Invert all its digits.
3364+
3365+
The self must be logical number.
3366+
"""
33233367
if context is None:
33243368
context = getcontext()
33253369
return self.logical_xor(_dec_from_triple(0,'1'*context.prec,0),
33263370
context)
33273371

33283372
def logical_or(self, other, context=None):
3329-
"""Applies an 'or' operation between self and other's digits."""
3373+
"""Applies an 'or' operation between self and other's digits.
3374+
3375+
Both self and other must be logical numbers.
3376+
"""
33303377
if context is None:
33313378
context = getcontext()
33323379

@@ -3343,7 +3390,10 @@ def logical_or(self, other, context=None):
33433390
return _dec_from_triple(0, result.lstrip('0') or '0', 0)
33443391

33453392
def logical_xor(self, other, context=None):
3346-
"""Applies an 'xor' operation between self and other's digits."""
3393+
"""Applies an 'xor' operation between self and other's digits.
3394+
3395+
Both self and other must be logical numbers.
3396+
"""
33473397
if context is None:
33483398
context = getcontext()
33493399

@@ -6058,7 +6108,7 @@ def _convert_for_comparison(self, other, equality_op=False):
60586108
(?P<diag>\d*) # with (possibly empty) diagnostic info.
60596109
)
60606110
# \s*
6061-
\Z
6111+
\z
60626112
""", re.VERBOSE | re.IGNORECASE).match
60636113

60646114
_all_zeros = re.compile('0*$').match
@@ -6082,11 +6132,15 @@ def _convert_for_comparison(self, other, equality_op=False):
60826132
(?P<no_neg_0>z)?
60836133
(?P<alt>\#)?
60846134
(?P<zeropad>0)?
6085-
(?P<minimumwidth>(?!0)\d+)?
6086-
(?P<thousands_sep>,)?
6087-
(?:\.(?P<precision>0|(?!0)\d+))?
6135+
(?P<minimumwidth>\d+)?
6136+
(?P<thousands_sep>[,_])?
6137+
(?:\.
6138+
(?=[\d,_]) # lookahead for digit or separator
6139+
(?P<precision>\d+)?
6140+
(?P<frac_separators>[,_])?
6141+
)?
60886142
(?P<type>[eEfFgGn%])?
6089-
\Z
6143+
\z
60906144
""", re.VERBOSE|re.DOTALL)
60916145

60926146
del re
@@ -6177,6 +6231,9 @@ def _parse_format_specifier(format_spec, _localeconv=None):
61776231
format_dict['grouping'] = [3, 0]
61786232
format_dict['decimal_point'] = '.'
61796233

6234+
if format_dict['frac_separators'] is None:
6235+
format_dict['frac_separators'] = ''
6236+
61806237
return format_dict
61816238

61826239
def _format_align(sign, body, spec):
@@ -6296,6 +6353,11 @@ def _format_number(is_negative, intpart, fracpart, exp, spec):
62966353

62976354
sign = _format_sign(is_negative, spec)
62986355

6356+
frac_sep = spec['frac_separators']
6357+
if fracpart and frac_sep:
6358+
fracpart = frac_sep.join(fracpart[pos:pos + 3]
6359+
for pos in range(0, len(fracpart), 3))
6360+
62996361
if fracpart or spec['alt']:
63006362
fracpart = spec['decimal_point'] + fracpart
63016363

Lib/decimal.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100

101101
try:
102102
from _decimal import *
103-
from _decimal import __version__
104-
from _decimal import __libmpdec_version__
103+
from _decimal import __version__ # noqa: F401
104+
from _decimal import __libmpdec_version__ # noqa: F401
105105
except ImportError:
106106
import _pydecimal
107107
import sys

0 commit comments

Comments
 (0)