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' ,
8383 MAX_PREC = 999999999999999999
8484 MAX_EMAX = 999999999999999999
8585 MIN_EMIN = - 999999999999999999
86+ IEEE_CONTEXT_MAX_BITS = 512
8687else :
8788 MAX_PREC = 425000000
8889 MAX_EMAX = 425000000
8990 MIN_EMIN = - 425000000
91+ IEEE_CONTEXT_MAX_BITS = 256
9092
9193MIN_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
60926146del 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
61826239def _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
0 commit comments