summaryrefslogtreecommitdiff
path: root/modules/language/python/module
diff options
context:
space:
mode:
authorStefan Israelsson Tampe <stefan.itampe@gmail.com>2018-07-03 16:56:51 +0200
committerStefan Israelsson Tampe <stefan.itampe@gmail.com>2018-07-03 16:56:51 +0200
commit144400ef5ebbc09834c658576c233f08a08c6fad (patch)
tree2bde75d671e88e8788bef936b51ed471b77140cd /modules/language/python/module
parentba256d9aaabbe71a8c526585e22d455a9d2066fd (diff)
more work on decimal
Diffstat (limited to 'modules/language/python/module')
-rw-r--r--modules/language/python/module/decimal.scm2309
1 files changed, 1227 insertions, 1082 deletions
diff --git a/modules/language/python/module/decimal.scm b/modules/language/python/module/decimal.scm
index 5ec8295..a71b990 100644
--- a/modules/language/python/module/decimal.scm
+++ b/modules/language/python/module/decimal.scm
@@ -4162,47 +4162,58 @@
;; of the formatting to the _format_number function
(_format_number (ref self '_sign) intpart fracpart exp spec))))))))
-def _dec_from_triple(sign, coefficient, exponent, special=False):
- """Create a decimal instance directly, without any validation,
+(define _dec_from_triple
+ (lam (sign coefficient exponent (= special #f))
+ "Create a decimal instance directly, without any validation,
normalization (e.g. removal of leading zeros) or argument
conversion.
This function is for *internal use only*.
- """
+ "
- self = object.__new__(Decimal)
- self._sign = sign
- self._int = coefficient
- self._exp = exponent
- self._is_special = special
+ (let ((self ((ref object '__new__) Decimal)))
+ (set self '_sign sign)
+ (set self '_int coefficient)
+ (set self '_exp exponent)
+ (set self '_is_special special)
- return self
+ self)))
-# Register Decimal as a kind of Number (an abstract base class).
-# However, do not register it as Real (because Decimals are not
-# interoperable with floats).
-_numbers.Number.register(Decimal)
+;; Register Decimal as a kind of Number (an abstract base class).
+;; However, do not register it as Real (because Decimals are not
+;; interoperable with floats).
+;; _numbers.Number.register(Decimal)
-##### Context class #######################################################
+;; ##### Context class #######################################################
-class _ContextManager(object):
- """Context manager class to support localcontext().
+(define-python-class _ContextManager (object)
+ "Context manager class to support localcontext().
Sets a copy of the supplied context in __enter__() and restores
the previous decimal context in __exit__()
- """
- def __init__(self, new_context):
- self.new_context = new_context.copy()
- def __enter__(self):
- self.saved_context = getcontext()
- setcontext(self.new_context)
- return self.new_context
- def __exit__(self, t, v, tb):
- setcontext(self.saved_context)
-
-class Context(object):
- """Contains the context for a Decimal instance.
+ "
+ (define __init__
+ (lambda (self new_context)
+ (set self 'new_context ((ref new_context 'copy)))))
+
+ (define __enter__
+ (lambda (self)
+ (set self 'saved_context (getcontext))
+ (setcontext (ref self 'new_context))
+ (ref self 'new_context)))
+
+ (define __exit__
+ (lambda (self t v tb)
+ (setcontext (ref self 'saved_context)))))
+
+(define DefaultContext #f)
+
+(define-syntax-rule (setq s q m)
+ (set s 'q (if (eq? q None) (ref m 'q) q)))
+
+(define-python-class Context (object)
+ "Contains the context for a Decimal instance.
Contains:
prec - precision (for use in rounding, division, square roots..)
@@ -4218,197 +4229,239 @@ class Context(object):
capitals - If 1, 1*10^1 is printed as 1E+1.
If 0, printed as 1e1
clamp - If 1, change exponents if too high (Default 0)
- """
+ "
- def __init__(self, prec=None, rounding=None, Emin=None, Emax=None,
- capitals=None, clamp=None, flags=None, traps=None,
- _ignored_flags=None):
- # Set defaults; for everything except flags and _ignored_flags,
- # inherit from DefaultContext.
- try:
- dc = DefaultContext
- except NameError:
- pass
-
- self.prec = prec if prec is not None else dc.prec
- self.rounding = rounding if rounding is not None else dc.rounding
- self.Emin = Emin if Emin is not None else dc.Emin
- self.Emax = Emax if Emax is not None else dc.Emax
- self.capitals = capitals if capitals is not None else dc.capitals
- self.clamp = clamp if clamp is not None else dc.clamp
-
- if _ignored_flags is None:
- self._ignored_flags = []
- else:
- self._ignored_flags = _ignored_flags
-
- if traps is None:
- self.traps = dc.traps.copy()
- elif not isinstance(traps, dict):
- self.traps = dict((s, int(s in traps)) for s in _signals + traps)
- else:
- self.traps = traps
-
- if flags is None:
- self.flags = dict.fromkeys(_signals, 0)
- elif not isinstance(flags, dict):
- self.flags = dict((s, int(s in flags)) for s in _signals + flags)
- else:
- self.flags = flags
-
- def _set_integer_check(self, name, value, vmin, vmax):
- if not isinstance(value, int):
- raise TypeError("%s must be an integer" % name)
- if vmin == '-inf':
- if value > vmax:
- raise ValueError("%s must be in [%s, %d]. got: %s" % (name, vmin, vmax, value))
- elif vmax == 'inf':
- if value < vmin:
- raise ValueError("%s must be in [%d, %s]. got: %s" % (name, vmin, vmax, value))
- else:
- if value < vmin or value > vmax:
- raise ValueError("%s must be in [%d, %d]. got %s" % (name, vmin, vmax, value))
- return object.__setattr__(self, name, value)
-
- def _set_signal_dict(self, name, d):
- if not isinstance(d, dict):
- raise TypeError("%s must be a signal dict" % d)
- for key in d:
- if not key in _signals:
- raise KeyError("%s is not a valid signal dict" % d)
- for key in _signals:
- if not key in d:
- raise KeyError("%s is not a valid signal dict" % d)
- return object.__setattr__(self, name, d)
-
- def __setattr__(self, name, value):
- if name == 'prec':
- return self._set_integer_check(name, value, 1, 'inf')
- elif name == 'Emin':
- return self._set_integer_check(name, value, '-inf', 0)
- elif name == 'Emax':
- return self._set_integer_check(name, value, 0, 'inf')
- elif name == 'capitals':
- return self._set_integer_check(name, value, 0, 1)
- elif name == 'clamp':
- return self._set_integer_check(name, value, 0, 1)
- elif name == 'rounding':
- if not value in _rounding_modes:
- # raise TypeError even for strings to have consistency
- # among various implementations.
- raise TypeError("%s: invalid rounding mode" % value)
- return object.__setattr__(self, name, value)
- elif name == 'flags' or name == 'traps':
- return self._set_signal_dict(name, value)
- elif name == '_ignored_flags':
- return object.__setattr__(self, name, value)
- else:
- raise AttributeError(
- "'decimal.Context' object has no attribute '%s'" % name)
-
- def __delattr__(self, name):
- raise AttributeError("%s cannot be deleted" % name)
-
- # Support for pickling, copy, and deepcopy
- def __reduce__(self):
- flags = [sig for sig, v in self.flags.items() if v]
- traps = [sig for sig, v in self.traps.items() if v]
- return (self.__class__,
- (self.prec, self.rounding, self.Emin, self.Emax,
- self.capitals, self.clamp, flags, traps))
-
- def __repr__(self):
- """Show the current context."""
- s = []
- s.append('Context(prec=%(prec)d, rounding=%(rounding)s, '
- 'Emin=%(Emin)d, Emax=%(Emax)d, capitals=%(capitals)d, '
- 'clamp=%(clamp)d'
- % vars(self))
- names = [f.__name__ for f, v in self.flags.items() if v]
- s.append('flags=[' + ', '.join(names) + ']')
- names = [t.__name__ for t, v in self.traps.items() if v]
- s.append('traps=[' + ', '.join(names) + ']')
- return ', '.join(s) + ')'
-
- def clear_flags(self):
- """Reset all flags to zero"""
- for flag in self.flags:
- self.flags[flag] = 0
-
- def clear_traps(self):
- """Reset all traps to zero"""
- for flag in self.traps:
- self.traps[flag] = 0
-
- def _shallow_copy(self):
- """Returns a shallow copy from self."""
- nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
- self.capitals, self.clamp, self.flags, self.traps,
- self._ignored_flags)
- return nc
-
- def copy(self):
- """Returns a deep copy from self."""
- nc = Context(self.prec, self.rounding, self.Emin, self.Emax,
- self.capitals, self.clamp,
- self.flags.copy(), self.traps.copy(),
- self._ignored_flags)
- return nc
- __copy__ = copy
-
- def _raise_error(self, condition, explanation = None, *args):
- """Handles an error
+ (define __init__
+ (lam (self (= prec None) (= rounding None) (= Emin None)
+ (= Emax None) (= capitals None) (= clamp None)
+ (= flags None) (= traps None) (= _ignored_flags None))
+ ;; Set defaults; for everything except flags and _ignored_flags,
+ ;; inherit from DefaultContext.
+ (let ((dc DefaultContext))
+ (setq self prec dc)
+ (setq self rounding dc)
+ (setq self Emin dc)
+ (setq self Emax dc)
+ (setq self capitals dc)
+ (setq self clamp dc)
+
+ (set self '_ignored_flags
+ (if (eq? _ignored_flags None)
+ (py-list)
+ _ignored_flags))
+ (set self 'traps
+ (cond
+ ((eq? traps None)
+ ((ref (ref dc traps) 'copy)))
+ ((not (isinstance traps dict))
+ (dict (for ((s : (+ _signals traps))) ((l '()))
+ (cons (list s (int (in s traps))) l)
+ #:final (reverse l))))
+ (else traps)))
+
+ (set self 'flags
+ (cond
+ ((eq? flags None)
+ ((ref dict 'fromkeys) _signals 0))
+ ((not (isinstance flags dict))
+ (dict (for ((s : (+ _signals flags))) ((l '()))
+ (cons (list s (int (in s flags))) l)
+ #:final (reverse l))))
+ (else flags))))))
+
+ (define _set_integer_check
+ (lambda (self name value vmin vmax)
+ (if (not (isinstance value int))
+ (raise (TypeError (format #f "~a must be an integer" name))))
+
+ (cond
+ ((equal? vmin "-inf")
+ (if (> value vmax)
+ (raise (ValueError (format #f "~a must be in [~a, ~a]. got: ~a"
+ name vmin vmax value)))))
+ ((equal? vmax "inf")
+ (if (< value vmin)
+ (raise (ValueError (format #f "~a must be in [~a, ~a]. got: ~a"
+ name vmin vmax value)))))
+ (else
+ (if (or (< value vmin) (> value vmax))
+ (raise (ValueError (format #f "~a must be in [~a, ~a]. got ~a"
+ name vmin vmax value))))))
+ (rawset self (string->symbol name) value)))
+
+ (define _set_signal_dict
+ (lambda (self name d)
+ (if (not (isinstance d dict))
+ (raise (TypeError (format #f "~a must be a signal dict" d))))
+
+ (for ((key : d)) ()
+ (if (not (in key _signals))
+ (raise (KeyError (format #f "~a is not a valid signal dict"
+ d)))))
+ (for ((key : _signals)) ()
+ (if (not (in key d))
+ (raise (KeyError (format #f "~a is not a valid signal dict"
+ d)))))
+ (rawset self (string->symbol name) d)))
+
+ (define __setattr__
+ (lambda (self name value)
+ (cond
+ ((equal? name "prec")
+ ((ref self '_set_integer_check) name value 1 "inf"))
+ ((equal? name "Emin")
+ ((ref self '_set_integer_check) name value "-inf" 0))
+ ((equal? name "Emax")
+ ((ref self '_set_integer_check) name value 0 "inf"))
+ ((equal? name "capitals")
+ ((ref self '_set_integer_check) name value 0 1))
+ ((equal? name "clamp")
+ ((ref self '_set_integer_check) name value 0 1))
+ ((equal? name "rounding")
+ (if (not (member (string->symbol value) _rounding_modes))
+ ;; raise TypeError even for strings to have consistency
+ ;; among various implementations.
+ (raise (TypeError (format #f "~a: invalid rounding mode" value))))
+ (rawset self (string->symbol name) (string->symbol value)))
+ ((or (equal? name "flags") (equal? name "traps"))
+ ((ref self '_set_signal_dict) name value))
+ ((equal? name "_ignored_flags")
+ (rawset self (string->symbol name) value))
+ (else
+ (raise (AttributeError
+ (format #f
+ "'decimal.Context' object has no attribute '~a'"
+ name)))))))
+
+ (define __delattr__
+ (lambda (self name)
+ (raise (AttributeError (format #f "~a cannot be deleted" name)))))
+
+ ;;# Support for pickling, copy, and deepcopy
+ ;;def __reduce__(self):
+ ;; flags = [sig for sig, v in self.flags.items() if v]
+ ;; traps = [sig for sig, v in self.traps.items() if v]
+ ;; return (self.__class__,
+ ;; (self.prec, self.rounding, self.Emin, self.Emax,
+ ;; self.capitals, self.clamp, flags, traps))
+
+ (define __repr__
+ (lambda (self)
+ "Show the current context."
+ (format #f "Context(prec=~a, rounding=~a, Emin=~a, Emax=~a capitals=~a clamp=~a, flags=~a, traps=~a)"
+ (ref self 'prec)
+ (ref self 'rounding)
+ (ref self 'Emin)
+ (ref self 'Emax)
+ (ref self 'capitals)
+ (ref self 'clamp)
+ (for ((k v : (ref self 'flags))) ((l '()))
+ (cons k l)
+ #:final (reverse l))
+ (for ((k v : (ref self 'traps))) ((l '()))
+ (cons k l)
+ #:final (reverse l)))))
+
+ (define clear_flags
+ (lambda (self)
+ "Reset all flags to zero"
+ (for ((flag : (ref self 'flags))) ()
+ (pylist-set! (ref self 'flags) flag 0))))
+
+ (define clear_traps
+ (lambda (self)
+ "Reset all traps to zero"
+ (for ((flag : (ref self 'traps))) ()
+ (pylist-set! (ref self 'traps) flag 0))))
+
+ (define _shallow_copy
+ (lambda (self)
+ "Returns a shallow copy from self."
+ (Context (ref self 'prec)
+ (ref self 'rounding)
+ (ref self 'Emin)
+ (ref self 'Emax)
+ (ref self 'capitals)
+ (ref self 'clamp)
+ (ref self 'flags)
+ (ref self 'traps)
+ (ref self '_ignored_flags))))
+
+ (define copy
+ (lambda (self)
+ "Returns a deep copy from self."
+ (Context (ref self 'prec)
+ (ref self 'rounding)
+ (ref self 'Emin)
+ (ref self 'Emax)
+ (ref self 'capitals)
+ (ref self 'clamp)
+ ((ref (ref self 'flags) 'copy))
+ ((ref (ref self 'traps) 'copy))
+ (ref self '_ignored_flags))))
+
+ (define __copy__ copy)
+
+ (define _raise_error
+ (lam (self condition (= explanation None) (* args))
+ "Handles an error
If the flag is in _ignored_flags, returns the default response.
Otherwise, it sets the flag, then, if the corresponding
trap_enabler is set, it reraises the exception. Otherwise, it returns
the default value after setting the flag.
- """
- error = _condition_map.get(condition, condition)
- if error in self._ignored_flags:
- # Don't touch the flag
- return error().handle(self, *args)
-
- self.flags[error] = 1
- if not self.traps[error]:
- # The errors define how to handle themselves.
- return condition().handle(self, *args)
-
- # Errors should only be risked on copies of the context
- # self._ignored_flags = []
- raise error(explanation)
-
- def _ignore_all_flags(self):
- """Ignore all flags, if they are raised"""
- return self._ignore_flags(*_signals)
-
- def _ignore_flags(self, *flags):
- """Ignore the flags, if they are raised"""
- # Do not mutate-- This way, copies of a context leave the original
- # alone.
- self._ignored_flags = (self._ignored_flags + list(flags))
- return list(flags)
-
- def _regard_flags(self, *flags):
- """Stop ignoring the flags, if they are raised"""
- if flags and isinstance(flags[0], (tuple,list)):
- flags = flags[0]
- for flag in flags:
- self._ignored_flags.remove(flag)
-
- # We inherit object.__hash__, so we must deny this explicitly
- __hash__ = None
-
- def Etiny(self):
- """Returns Etiny (= Emin - prec + 1)"""
- return int(self.Emin - self.prec + 1)
-
- def Etop(self):
- """Returns maximum exponent (= Emax - prec + 1)"""
- return int(self.Emax - self.prec + 1)
-
- def _set_rounding(self, type):
- """Sets the rounding type.
+ "
+ (let ((error ((ref _condition_map 'get) condition condition)))
+ (if (in error (ref self '_ignored_flags))
+ ;; Don't touch the flag
+ (py-apply (ref (error) 'handle) self (* args))
+ (begin
+ (pylist-set! (ref self 'flags) error 1)
+ (if (not (bool (pylist-ref (ref self 'traps) error)))
+ ;; The errors define how to handle themselves.
+ (py-apply (ref (condition) 'handle) self (* args))
+
+ ;; Errors should only be risked on copies of the context
+ ;; self._ignored_flags = []
+ (raise (error explanation))))))))
+
+ (define _ignore_all_flags
+ (lambda (self)
+ "Ignore all flags, if they are raised"
+ (py-apply (ref self '_ignore_flags) (*_signals))))
+
+ (define _ignore_flags
+ (lambda (self . flags)
+ "Ignore the flags, if they are raised"
+ ;; Do not mutate-- This way, copies of a context leave the original
+ ;; alone.
+ (set self '_ignored_flags (+ (ref self '_ignored_flags) (py-list flags)))
+ (py-list flags)))
+
+ (define _regard_flags
+ (lambda (self . flags)
+ "Stop ignoring the flags, if they are raised"
+ (let ((flags
+ (if (and (pair? flags) (isinstance (car flags) (tuple,list)))
+ (car flags)
+ flags)))
+ (for ((flag : flags)) ()
+ ((ref (ref self '_ignored_flags) 'remove) flag)))))
+
+ ;; We inherit object.__hash__, so we must deny this explicitly
+ (define __hash__ None)
+
+ (define Etiny
+ (lambda (self)
+ "Returns Etiny (= Emin - prec + 1)"
+ (int (+ (- (ref self 'Emin) (ref self 'prec)) 1))))
+
+ (define (Etop self)
+ "Returns maximum exponent (= Emax - prec + 1)"
+ (int (+ (- (ref self 'Emax) (ref self 'prec)) 1)))
+
+ (define (_set_rounding self type)
+ "Sets the rounding type.
Sets the rounding type, and returns the current (previous)
rounding type. Often used like:
@@ -4421,30 +4474,33 @@ class Context(object):
context._set_rounding(rounding)
This will make it round up for that operation.
- """
- rounding = self.rounding
- self.rounding = type
- return rounding
+ "
+ (let ((rounding (ref self 'rounding)))
+ (set self 'rounding type)
+ rounding))
- def create_decimal(self, num='0'):
- """Creates a new Decimal instance but using self as context.
+ (define create_decimal
+ (lam (self (= num "0"))
+ "Creates a new Decimal instance but using self as context.
This method implements the to-number operation of the
- IBM Decimal specification."""
-
- if isinstance(num, str) and (num != num.strip() or '_' in num):
- return self._raise_error(ConversionSyntax,
- "trailing or leading whitespace and "
- "underscores are not permitted.")
-
- d = Decimal(num, context=self)
- if d._isnan() and len(d._int) > self.prec - self.clamp:
- return self._raise_error(ConversionSyntax,
- "diagnostic info too long in NaN")
- return d._fix(self)
-
- def create_decimal_from_float(self, f):
- """Creates a new Decimal instance from a float but rounding using self
+ IBM Decimal specification."
+
+ (if (or (and (isinstance num str) (not (equal? num ((ref num 'strip)))))
+ (in "_" num))
+ ((ref self '_raise_error) ConversionSyntax
+ "trailing or leading whitespace and "
+ "underscores are not permitted.")
+ (let ((d (Decimal num #:context self)))
+ (if (and ((ref d '_isnan)) (> (len (ref d '_int)) (- (ref self 'prec)
+ (ref self 'clamp))))
+ ((ref self '_raise_error) ConversionSyntax
+ "diagnostic info too long in NaN")
+ ((ref d '_fix) self))))))
+
+ (define create_decimal_from_float
+ (lambda (self f)
+ "Creates a new Decimal instance from a float but rounding using self
as the context.
>>> context = Context(prec=5, rounding=ROUND_DOWN)
@@ -4456,13 +4512,14 @@ class Context(object):
...
decimal.Inexact: None
- """
- d = Decimal.from_float(f) # An exact conversion
- return d._fix(self) # Apply the context rounding
+ "
+ (let ((d ((ref Decimal 'from_float) f))) ; An exact conversion
+ ((ref d '_fix) self)))) ; Apply the context rounding
- # Methods
- def abs(self, a):
- """Returns the absolute value of the operand.
+ ;; Methods
+ (define abs
+ (lambda (self a)
+ "Returns the absolute value of the operand.
If the operand is negative, the result is the same as using the minus
operation on the operand. Otherwise, the result is the same as using
@@ -4478,12 +4535,13 @@ class Context(object):
Decimal('101.5')
>>> ExtendedContext.abs(-1)
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- return a.__abs__(context=self)
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a '__abs__) #:context self))))
- def add(self, a, b):
- """Return the sum of the two operands.
+ (define add
+ (lambda (self a b)
+ "Return the sum of the two operands.
>>> ExtendedContext.add(Decimal('12'), Decimal('7.00'))
Decimal('19.00')
@@ -4495,32 +4553,35 @@ class Context(object):
Decimal('13')
>>> ExtendedContext.add(5, 5)
Decimal('10')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__add__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__add__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (fromat #f "Unable to convert ~a to Decimal" b)))
+ r))))
- def _apply(self, a):
- return str(a._fix(self))
+ (define _apply
+ (lambda (self a)
+ (str ((ref a '_fix) self))))
- def canonical(self, a):
- """Returns the same Decimal object.
+ (define canonical
+ (lambda (self a)
+ "Returns the same Decimal object.
As we do not have different encodings for the same number, the
received object already is in its canonical form.
>>> ExtendedContext.canonical(Decimal('2.50'))
Decimal('2.50')
- """
- if not isinstance(a, Decimal):
- raise TypeError("canonical requires a Decimal as an argument.")
- return a.canonical()
+ "
+ (if (not (isinstance a Decimal))
+ (raise (TypeError "canonical requires a Decimal as an argument.")))
+
+ ((ref a 'canonical))))
- def compare(self, a, b):
- """Compares values numerically.
+ (define compare
+ (lambda (self a b):
+ "Compares values numerically.
If the signs of the operands differ, a value representing each operand
('-1' if the operand is less than zero, '0' if the operand is zero or
@@ -4551,12 +4612,13 @@ class Context(object):
Decimal('-1')
>>> ExtendedContext.compare(1, Decimal(2))
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.compare(b, context=self)
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'compare) b #:context self))))
- def compare_signal(self, a, b):
- """Compares the values of the two operands numerically.
+ (define compare_signal
+ (lambda (self a b)
+ "Compares the values of the two operands numerically.
It's pretty much like compare(), but all NaNs signal, with signaling
NaNs taking precedence over quiet NaNs.
@@ -4586,12 +4648,13 @@ class Context(object):
Decimal('-1')
>>> c.compare_signal(-1, Decimal(2))
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.compare_signal(b, context=self)
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'compare_signal) b #:context self))))
- def compare_total(self, a, b):
- """Compares two operands using their abstract representation.
+ (define compare_total
+ (lambda (self a b)
+ "Compares two operands using their abstract representation.
This is not like the standard compare, which use their numerical
value. Note that a total ordering is defined for all possible abstract
@@ -4615,20 +4678,22 @@ class Context(object):
Decimal('-1')
>>> ExtendedContext.compare_total(1, Decimal(2))
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.compare_total(b)
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'compare_total) b #:context self))))
- def compare_total_mag(self, a, b):
- """Compares two operands using their abstract representation ignoring sign.
+ (define compare_total_mag
+ (lambda (self a b)
+ "Compares two operands using their abstract representation ignoring sign.
Like compare_total, but with operand's sign ignored and assumed to be 0.
- """
- a = _convert_other(a, raiseit=True)
- return a.compare_total_mag(b)
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'compare_total_mag) b #:context self))))
- def copy_abs(self, a):
- """Returns a copy of the operand with the sign set to 0.
+ (define copy_abs
+ (lambda (self a)
+ "Returns a copy of the operand with the sign set to 0.
>>> ExtendedContext.copy_abs(Decimal('2.1'))
Decimal('2.1')
@@ -4636,12 +4701,13 @@ class Context(object):
Decimal('100')
>>> ExtendedContext.copy_abs(-1)
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- return a.copy_abs()
-
- def copy_decimal(self, a):
- """Returns a copy of the decimal object.
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'copy_abs)))))
+
+ (define copy_decimal
+ (lambda (self a)
+ "Returns a copy of the decimal object.
>>> ExtendedContext.copy_decimal(Decimal('2.1'))
Decimal('2.1')
@@ -4649,12 +4715,13 @@ class Context(object):
Decimal('-1.00')
>>> ExtendedContext.copy_decimal(1)
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- return Decimal(a)
-
- def copy_negate(self, a):
- """Returns a copy of the operand with the sign inverted.
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ (Decimal a))))
+
+ (define copy_negate
+ (lambda (self a)
+ "Returns a copy of the operand with the sign inverted.
>>> ExtendedContext.copy_negate(Decimal('101.5'))
Decimal('-101.5')
@@ -4662,12 +4729,13 @@ class Context(object):
Decimal('101.5')
>>> ExtendedContext.copy_negate(1)
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.copy_negate()
-
- def copy_sign(self, a, b):
- """Copies the second operand's sign to the first one.
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'copy_negate)))))
+
+ (define copy_sign
+ (lambda (self a b)
+ "Copies the second operand's sign to the first one.
In detail, it returns a copy of the first operand with the sign
equal to the sign of the second operand.
@@ -4686,12 +4754,13 @@ class Context(object):
Decimal('-1')
>>> ExtendedContext.copy_sign(1, Decimal(-2))
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.copy_sign(b)
+ "
+ (let ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'copy_sign) b))))
- def divide(self, a, b):
- """Decimal division in a specified context.
+ (define divide
+ (lambda (self a b)
+ "Decimal division in a specified context.
>>> ExtendedContext.divide(Decimal('1'), Decimal('3'))
Decimal('0.333333333')
@@ -4719,16 +4788,16 @@ class Context(object):
Decimal('1')
>>> ExtendedContext.divide(5, Decimal(5))
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__truediv__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
-
- def divide_int(self, a, b):
- """Divides two numbers and returns the integer part of the result.
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__truediv__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
+
+ (define divide_int
+ (lambda (self a b)
+ "Divides two numbers and returns the integer part of the result.
>>> ExtendedContext.divide_int(Decimal('2'), Decimal('3'))
Decimal('0')
@@ -4742,16 +4811,16 @@ class Context(object):
Decimal('3')
>>> ExtendedContext.divide_int(10, Decimal(3))
Decimal('3')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__floordiv__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
-
- def divmod(self, a, b):
- """Return (a // b, a % b).
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__floordiv__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
+
+ (define divmod
+ (lambda (self a b)
+ "Return (a // b, a % b).
>>> ExtendedContext.divmod(Decimal(8), Decimal(3))
(Decimal('2'), Decimal('2'))
@@ -4763,16 +4832,16 @@ class Context(object):
(Decimal('2'), Decimal('0'))
>>> ExtendedContext.divmod(8, Decimal(4))
(Decimal('2'), Decimal('0'))
- """
- a = _convert_other(a, raiseit=True)
- r = a.__divmod__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__divmod__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
- def exp(self, a):
- """Returns e ** a.
+ (define exp
+ (lambda (self a)
+ "Returns e ** a.
>>> c = ExtendedContext.copy()
>>> c.Emin = -999
@@ -4791,12 +4860,13 @@ class Context(object):
Decimal('Infinity')
>>> c.exp(10)
Decimal('22026.4658')
- """
- a =_convert_other(a, raiseit=True)
- return a.exp(context=self)
-
- def fma(self, a, b, c):
- """Returns a multiplied by b, plus c.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'exp) #:context self))))
+
+ (define fma
+ (lambda (self a b c)
+ "Returns a multiplied by b, plus c.
The first two operands are multiplied together, using multiply,
the third operand is then added to the result of that
@@ -4814,25 +4884,27 @@ class Context(object):
Decimal('7')
>>> ExtendedContext.fma(1, 3, Decimal(4))
Decimal('7')
- """
- a = _convert_other(a, raiseit=True)
- return a.fma(b, c, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'fma) b c #:context self))))
- def is_canonical(self, a):
- """Return True if the operand is canonical; otherwise return False.
+ (define is_canonical
+ (lambda (self a)
+ "Return True if the operand is canonical; otherwise return False.
Currently, the encoding of a Decimal instance is always
canonical, so this method returns True for any Decimal.
>>> ExtendedContext.is_canonical(Decimal('2.50'))
True
- """
- if not isinstance(a, Decimal):
- raise TypeError("is_canonical requires a Decimal as an argument.")
- return a.is_canonical()
+ "
+ (if (not (isinstance a Decimal))
+ (raise (TypeError "is_canonical requires a Decimal as an argument."))
+ ((ref a 'is_canonical)))))
- def is_finite(self, a):
- """Return True if the operand is finite; otherwise return False.
+ (define is_finite
+ (lambda (self a)
+ "Return True if the operand is finite; otherwise return False.
A Decimal instance is considered finite if it is neither
infinite nor a NaN.
@@ -4849,12 +4921,13 @@ class Context(object):
False
>>> ExtendedContext.is_finite(1)
True
- """
- a = _convert_other(a, raiseit=True)
- return a.is_finite()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'finite)))))
- def is_infinite(self, a):
- """Return True if the operand is infinite; otherwise return False.
+ (define is_infinite
+ (lambda (self a)
+ "Return True if the operand is infinite; otherwise return False.
>>> ExtendedContext.is_infinite(Decimal('2.50'))
False
@@ -4864,12 +4937,13 @@ class Context(object):
False
>>> ExtendedContext.is_infinite(1)
False
- """
- a = _convert_other(a, raiseit=True)
- return a.is_infinite()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_infinite)))))
- def is_nan(self, a):
- """Return True if the operand is a qNaN or sNaN;
+ (define is_nan
+ (lambda (self a)
+ "Return True if the operand is a qNaN or sNaN;
otherwise return False.
>>> ExtendedContext.is_nan(Decimal('2.50'))
@@ -4880,12 +4954,13 @@ class Context(object):
True
>>> ExtendedContext.is_nan(1)
False
- """
- a = _convert_other(a, raiseit=True)
- return a.is_nan()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_nan)))))
- def is_normal(self, a):
- """Return True if the operand is a normal number;
+ (define is_normal
+ (lambda (self a)
+ "Return True if the operand is a normal number;
otherwise return False.
>>> c = ExtendedContext.copy()
@@ -4903,12 +4978,13 @@ class Context(object):
False
>>> c.is_normal(1)
True
- """
- a = _convert_other(a, raiseit=True)
- return a.is_normal(context=self)
-
- def is_qnan(self, a):
- """Return True if the operand is a quiet NaN; otherwise return False.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_normal) #:context self))))
+
+ (define is_qnan
+ (lambda (self a)
+ "Return True if the operand is a quiet NaN; otherwise return False.
>>> ExtendedContext.is_qnan(Decimal('2.50'))
False
@@ -4918,12 +4994,13 @@ class Context(object):
False
>>> ExtendedContext.is_qnan(1)
False
- """
- a = _convert_other(a, raiseit=True)
- return a.is_qnan()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_qnan)))))
- def is_signed(self, a):
- """Return True if the operand is negative; otherwise return False.
+ (define is_signed
+ (lambda (self a)
+ "Return True if the operand is negative; otherwise return False.
>>> ExtendedContext.is_signed(Decimal('2.50'))
False
@@ -4935,12 +5012,14 @@ class Context(object):
False
>>> ExtendedContext.is_signed(-8)
True
- """
- a = _convert_other(a, raiseit=True)
- return a.is_signed()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_signed)))))
- def is_snan(self, a):
- """Return True if the operand is a signaling NaN;
+
+ (define is_snan
+ (lambda (self a)
+ "Return True if the operand is a signaling NaN;
otherwise return False.
>>> ExtendedContext.is_snan(Decimal('2.50'))
@@ -4951,12 +5030,14 @@ class Context(object):
True
>>> ExtendedContext.is_snan(1)
False
- """
- a = _convert_other(a, raiseit=True)
- return a.is_snan()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_snan)))))
- def is_subnormal(self, a):
- """Return True if the operand is subnormal; otherwise return False.
+
+ (define is_subnormal
+ (lambda (self a)
+ "Return True if the operand is subnormal; otherwise return False.
>>> c = ExtendedContext.copy()
>>> c.Emin = -999
@@ -4973,12 +5054,13 @@ class Context(object):
False
>>> c.is_subnormal(1)
False
- """
- a = _convert_other(a, raiseit=True)
- return a.is_subnormal(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_subnormal) #:context self))))
- def is_zero(self, a):
- """Return True if the operand is a zero; otherwise return False.
+ (define is_zero
+ (lambda (self a)
+ "Return True if the operand is a zero; otherwise return False.
>>> ExtendedContext.is_zero(Decimal('0'))
True
@@ -4990,12 +5072,13 @@ class Context(object):
False
>>> ExtendedContext.is_zero(0)
True
- """
- a = _convert_other(a, raiseit=True)
- return a.is_zero()
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'is_zero)))))
- def ln(self, a):
- """Returns the natural (base e) logarithm of the operand.
+ (define ln
+ (lambda (self a)
+ "Returns the natural (base e) logarithm of the operand.
>>> c = ExtendedContext.copy()
>>> c.Emin = -999
@@ -5012,12 +5095,13 @@ class Context(object):
Decimal('Infinity')
>>> c.ln(1)
Decimal('0')
- """
- a = _convert_other(a, raiseit=True)
- return a.ln(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'ln) #:context self))))
- def log10(self, a):
- """Returns the base 10 logarithm of the operand.
+ (define log10
+ (lambda (self a)
+ "Returns the base 10 logarithm of the operand.
>>> c = ExtendedContext.copy()
>>> c.Emin = -999
@@ -5040,12 +5124,13 @@ class Context(object):
Decimal('-Infinity')
>>> c.log10(1)
Decimal('0')
- """
- a = _convert_other(a, raiseit=True)
- return a.log10(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'log10) #:context self))))
- def logb(self, a):
- """ Returns the exponent of the magnitude of the operand's MSD.
+ (define logb
+ (lambda (self a)
+ " Returns the exponent of the magnitude of the operand's MSD.
The result is the integer which is the exponent of the magnitude
of the most significant digit of the operand (as though the
@@ -5066,12 +5151,13 @@ class Context(object):
Decimal('1')
>>> ExtendedContext.logb(100)
Decimal('2')
- """
- a = _convert_other(a, raiseit=True)
- return a.logb(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'logb) #:context self))))
- def logical_and(self, a, b):
- """Applies the logical operation 'and' between each operand's digits.
+ (define logical_and
+ (lambda (self a b)
+ "Applies the logical operation 'and' between each operand's digits.
The operands must be both logical numbers.
@@ -5093,12 +5179,13 @@ class Context(object):
Decimal('100')
>>> ExtendedContext.logical_and(110, Decimal(1101))
Decimal('100')
- """
- a = _convert_other(a, raiseit=True)
- return a.logical_and(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'logical_and) b #:context self))))
- def logical_invert(self, a):
- """Invert all the digits in the operand.
+ (define logical_invert
+ (lambda (self a)
+ "Invert all the digits in the operand.
The operand must be a logical number.
@@ -5112,12 +5199,13 @@ class Context(object):
Decimal('10101010')
>>> ExtendedContext.logical_invert(1101)
Decimal('111110010')
- """
- a = _convert_other(a, raiseit=True)
- return a.logical_invert(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'logical_invert) #:context self))))
- def logical_or(self, a, b):
- """Applies the logical operation 'or' between each operand's digits.
+ (define logical_or
+ (lambda (self a b)
+ "Applies the logical operation 'or' between each operand's digits.
The operands must be both logical numbers.
@@ -5139,12 +5227,13 @@ class Context(object):
Decimal('1111')
>>> ExtendedContext.logical_or(110, Decimal(1101))
Decimal('1111')
- """
- a = _convert_other(a, raiseit=True)
- return a.logical_or(b, context=self)
-
- def logical_xor(self, a, b):
- """Applies the logical operation 'xor' between each operand's digits.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'logical_or) b #:context self))))
+
+ (define logical_xor
+ (lambda (self a b)
+ "Applies the logical operation 'xor' between each operand's digits.
The operands must be both logical numbers.
@@ -5166,12 +5255,13 @@ class Context(object):
Decimal('1011')
>>> ExtendedContext.logical_xor(110, Decimal(1101))
Decimal('1011')
- """
- a = _convert_other(a, raiseit=True)
- return a.logical_xor(b, context=self)
-
- def max(self, a, b):
- """max compares two values numerically and returns the maximum.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'logical_xor) b #:context self))))
+
+ (define max
+ (lambda (self a b)
+ "max compares two values numerically and returns the maximum.
If either operand is a NaN then the general rules apply.
Otherwise, the operands are compared as though by the compare
@@ -5193,12 +5283,13 @@ class Context(object):
Decimal('2')
>>> ExtendedContext.max(1, Decimal(2))
Decimal('2')
- """
- a = _convert_other(a, raiseit=True)
- return a.max(b, context=self)
-
- def max_mag(self, a, b):
- """Compares the values numerically with their sign ignored.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'max) b #:context self))))
+
+ (define max_mag
+ (lambda (self a b)
+ "Compares the values numerically with their sign ignored.
>>> ExtendedContext.max_mag(Decimal('7'), Decimal('NaN'))
Decimal('7')
@@ -5210,12 +5301,13 @@ class Context(object):
Decimal('-2')
>>> ExtendedContext.max_mag(1, Decimal(-2))
Decimal('-2')
- """
- a = _convert_other(a, raiseit=True)
- return a.max_mag(b, context=self)
-
- def min(self, a, b):
- """min compares two values numerically and returns the minimum.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'max_mag) b #:context self))))
+
+ (define min
+ (lambda (self a b)
+ "min compares two values numerically and returns the minimum.
If either operand is a NaN then the general rules apply.
Otherwise, the operands are compared as though by the compare
@@ -5237,12 +5329,13 @@ class Context(object):
Decimal('1')
>>> ExtendedContext.min(1, Decimal(29))
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- return a.min(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'min) b #:context self))))
- def min_mag(self, a, b):
- """Compares the values numerically with their sign ignored.
+ (define min_mag
+ (lambda (self a b)
+ "Compares the values numerically with their sign ignored.
>>> ExtendedContext.min_mag(Decimal('3'), Decimal('-2'))
Decimal('-2')
@@ -5254,12 +5347,13 @@ class Context(object):
Decimal('1')
>>> ExtendedContext.min_mag(1, Decimal(-2))
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- return a.min_mag(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'min_mag) b #:context self))))
- def minus(self, a):
- """Minus corresponds to unary prefix minus in Python.
+ (define minus
+ (lambda (self a)
+ "Minus corresponds to unary prefix minus in Python.
The operation is evaluated using the same rules as subtract; the
operation minus(a) is calculated as subtract('0', a) where the '0'
@@ -5271,12 +5365,13 @@ class Context(object):
Decimal('1.3')
>>> ExtendedContext.minus(1)
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.__neg__(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a '__neg__) #:context self))))
- def multiply(self, a, b):
- """multiply multiplies two operands.
+ (define multiply
+ (lambda (self a b)
+ "multiply multiplies two operands.
If either operand is a special value then the general rules apply.
Otherwise, the operands are multiplied together
@@ -5299,16 +5394,16 @@ class Context(object):
Decimal('49')
>>> ExtendedContext.multiply(7, Decimal(7))
Decimal('49')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__mul__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__mul__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
- def next_minus(self, a):
- """Returns the largest representable number smaller than a.
+ (define next_minus
+ (lambda (self a)
+ "Returns the largest representable number smaller than a.
>>> c = ExtendedContext.copy()
>>> c.Emin = -999
@@ -5323,12 +5418,13 @@ class Context(object):
Decimal('9.99999999E+999')
>>> c.next_minus(1)
Decimal('0.999999999')
- """
- a = _convert_other(a, raiseit=True)
- return a.next_minus(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'next_minus) #:context self))))
- def next_plus(self, a):
- """Returns the smallest representable number larger than a.
+ (define next_plus
+ (lambda (self a)
+ "Returns the smallest representable number larger than a.
>>> c = ExtendedContext.copy()
>>> c.Emin = -999
@@ -5343,12 +5439,13 @@ class Context(object):
Decimal('-9.99999999E+999')
>>> c.next_plus(1)
Decimal('1.00000001')
- """
- a = _convert_other(a, raiseit=True)
- return a.next_plus(context=self)
-
- def next_toward(self, a, b):
- """Returns the number closest to a, in direction towards b.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'next_plus) #:context self))))
+
+ (define next_toward
+ (lambda (self a b)
+ "Returns the number closest to a, in direction towards b.
The result is the closest representable number from the first
operand (but not the first operand) that is in the direction
@@ -5378,12 +5475,13 @@ class Context(object):
Decimal('1E-1007')
>>> c.next_toward(0, Decimal(1))
Decimal('1E-1007')
- """
- a = _convert_other(a, raiseit=True)
- return a.next_toward(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'next_toward) b #:context self))))
- def normalize(self, a):
- """normalize reduces an operand to its simplest form.
+ (define normalize
+ (lambda (self a)
+ "normalize reduces an operand to its simplest form.
Essentially a plus operation with all trailing zeros removed from the
result.
@@ -5402,12 +5500,13 @@ class Context(object):
Decimal('0')
>>> ExtendedContext.normalize(6)
Decimal('6')
- """
- a = _convert_other(a, raiseit=True)
- return a.normalize(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'normalize) #:context self))))
- def number_class(self, a):
- """Returns an indication of the class of the operand.
+ (define number_class
+ (lambda (self a)
+ "Returns an indication of the class of the operand.
The class is one of the following strings:
-sNaN
@@ -5452,12 +5551,13 @@ class Context(object):
'sNaN'
>>> c.number_class(123)
'+Normal'
- """
- a = _convert_other(a, raiseit=True)
- return a.number_class(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'number_class) #:context self))))
- def plus(self, a):
- """Plus corresponds to unary prefix plus in Python.
+ (define plus
+ (lambda (self a)
+ "Plus corresponds to unary prefix plus in Python.
The operation is evaluated using the same rules as add; the
operation plus(a) is calculated as add('0', a) where the '0'
@@ -5469,12 +5569,13 @@ class Context(object):
Decimal('-1.3')
>>> ExtendedContext.plus(-1)
Decimal('-1')
- """
- a = _convert_other(a, raiseit=True)
- return a.__pos__(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a '__pos__) #:context self))))
- def power(self, a, b, modulo=None):
- """Raises a to the power of b, to modulo if given.
+ (define power
+ (lam (self a b (= modulo None))
+ "Raises a to the power of b, to modulo if given.
With two arguments, compute a**b. If a is negative then b
must be integral. The result will be inexact unless b is
@@ -5545,16 +5646,16 @@ class Context(object):
Decimal('823543')
>>> ExtendedContext.power(7, Decimal(7), 2)
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__pow__(b, modulo, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__pow__) b modulo #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
- def quantize(self, a, b):
- """Returns a value equal to 'a' (rounded), having the exponent of 'b'.
+ (define quantize
+ (lambda (self a b)
+ "Returns a value equal to 'a' (rounded), having the exponent of 'b'.
The coefficient of the result is derived from that of the left-hand
operand. It may be rounded using the current rounding setting (if the
@@ -5607,20 +5708,22 @@ class Context(object):
Decimal('1')
>>> ExtendedContext.quantize(1, Decimal(2))
Decimal('1')
- """
- a = _convert_other(a, raiseit=True)
- return a.quantize(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'quantize) b #:context self))))
- def radix(self):
- """Just returns 10, as this is Decimal, :)
+ (define radix
+ (lambda (self)
+ "Just returns 10, as this is Decimal, :)
>>> ExtendedContext.radix()
Decimal('10')
- """
- return Decimal(10)
+ "
+ (Decimal 10)))
- def remainder(self, a, b):
- """Returns the remainder from integer division.
+ (define remainder
+ (lambda (self a b)
+ "Returns the remainder from integer division.
The result is the residue of the dividend after the operation of
calculating integer division as described for divide-integer, rounded
@@ -5649,16 +5752,16 @@ class Context(object):
Decimal('4')
>>> ExtendedContext.remainder(22, Decimal(6))
Decimal('4')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__mod__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
-
- def remainder_near(self, a, b):
- """Returns to be "a - b * n", where n is the integer nearest the exact
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__mod__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
+
+ (define remainder_near
+ (lambda (self a b)
+ "Returns to be 'a - b * n', where n is the integer nearest the exact
value of "x / b" (if two integers are equally near then the even one
is chosen). If the result is equal to 0 then its sign will be the
sign of a.
@@ -5687,12 +5790,13 @@ class Context(object):
Decimal('3')
>>> ExtendedContext.remainder_near(3, Decimal(11))
Decimal('3')
- """
- a = _convert_other(a, raiseit=True)
- return a.remainder_near(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'remainder_near) b #:context self))))
- def rotate(self, a, b):
- """Returns a rotated copy of a, b times.
+ (define rotate
+ (lambda (self a b)
+ "Returns a rotated copy of a, b times.
The coefficient of the result is a rotated copy of the digits in
the coefficient of the first operand. The number of places of
@@ -5716,12 +5820,13 @@ class Context(object):
Decimal('13333330')
>>> ExtendedContext.rotate(1333333, Decimal(1))
Decimal('13333330')
- """
- a = _convert_other(a, raiseit=True)
- return a.rotate(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'rotate) b #:context self))))
- def same_quantum(self, a, b):
- """Returns True if the two operands have the same exponent.
+ (define same_quantum
+ (lambda (self a b)
+ "Returns True if the two operands have the same exponent.
The result is never affected by either the sign or the coefficient of
either operand.
@@ -5740,12 +5845,13 @@ class Context(object):
True
>>> ExtendedContext.same_quantum(10000, Decimal(-1))
True
- """
- a = _convert_other(a, raiseit=True)
- return a.same_quantum(b)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'same_quantum) b #:context self))))
- def scaleb (self, a, b):
- """Returns the first operand after adding the second value its exp.
+ (define scaleb
+ (lambda (self a b)
+ "Returns the first operand after adding the second value its exp.
>>> ExtendedContext.scaleb(Decimal('7.50'), Decimal('-2'))
Decimal('0.0750')
@@ -5759,12 +5865,13 @@ class Context(object):
Decimal('1E+4')
>>> ExtendedContext.scaleb(1, Decimal(4))
Decimal('1E+4')
- """
- a = _convert_other(a, raiseit=True)
- return a.scaleb(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'scaleb) b #:context self))))
- def shift(self, a, b):
- """Returns a shifted copy of a, b times.
+ (define shift
+ (lambda (self a b)
+ "Returns a shifted copy of a, b times.
The coefficient of the result is a shifted copy of the digits
in the coefficient of the first operand. The number of places
@@ -5789,12 +5896,13 @@ class Context(object):
Decimal('888888800')
>>> ExtendedContext.shift(88888888, Decimal(2))
Decimal('888888800')
- """
- a = _convert_other(a, raiseit=True)
- return a.shift(b, context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'shift) b #:context self))))
- def sqrt(self, a):
- """Square root of a non-negative number to context precision.
+ (define sqrt
+ (lambda (self a)
+ "Square root of a non-negative number to context precision.
If the result must be inexact, it is rounded using the round-half-even
algorithm.
@@ -5821,12 +5929,13 @@ class Context(object):
Decimal('1.41421356')
>>> ExtendedContext.prec
9
- """
- a = _convert_other(a, raiseit=True)
- return a.sqrt(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'sqrt) #:context self))))
- def subtract(self, a, b):
- """Return the difference between the two operands.
+ (define subtract
+ (lambda (self a b)
+ "Return the difference between the two operands.
>>> ExtendedContext.subtract(Decimal('1.3'), Decimal('1.07'))
Decimal('0.23')
@@ -5840,16 +5949,16 @@ class Context(object):
Decimal('3')
>>> ExtendedContext.subtract(8, Decimal(5))
Decimal('3')
- """
- a = _convert_other(a, raiseit=True)
- r = a.__sub__(b, context=self)
- if r is NotImplemented:
- raise TypeError("Unable to convert %s to Decimal" % b)
- else:
- return r
+ "
+ (let* ((a (_convert_other a #:raiseit #t))
+ (r ((ref a '__sub__) b #:context self)))
+ (if (equal? r NotImplemented)
+ (raise (TypeError (format #t "Unable to convert ~a to Decimal" b)))
+ r))))
- def to_eng_string(self, a):
- """Convert to a string, using engineering notation if an exponent is needed.
+ (define to_eng_string
+ (lambda (self a)
+ "Convert to a string, using engineering notation if an exponent is needed.
Engineering notation has an exponent which is a multiple of 3. This
can leave up to 3 digits to the left of the decimal place and may
@@ -5872,20 +5981,22 @@ class Context(object):
>>> ExtendedContext.to_eng_string(Decimal('0E+1'))
'0.00E+3'
- """
- a = _convert_other(a, raiseit=True)
- return a.to_eng_string(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'to_eng_string) #:context self))))
- def to_sci_string(self, a):
- """Converts a number to a string, using scientific notation.
+ (define to_sci_string
+ (lambda (self a)
+ "Converts a number to a string, using scientific notation.
The operation is not affected by the context.
- """
- a = _convert_other(a, raiseit=True)
- return a.__str__(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a '__str__) #:context self))))
- def to_integral_exact(self, a):
- """Rounds to an integer.
+ (define to_integral_exact
+ (lambda (self a)
+ "Rounds to an integer.
When the operand has a negative exponent, the result is the same
as using the quantize() operation using the given operand as the
@@ -5910,12 +6021,13 @@ class Context(object):
Decimal('7.89E+77')
>>> ExtendedContext.to_integral_exact(Decimal('-Inf'))
Decimal('-Infinity')
- """
- a = _convert_other(a, raiseit=True)
- return a.to_integral_exact(context=self)
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'to_integral_exact) #:context self))))
- def to_integral_value(self, a):
- """Rounds to an integer.
+ (define to_integral_value
+ (lambda (self a)
+ "Rounds to an integer.
When the operand has a negative exponent, the result is the same
as using the quantize() operation using the given operand as the
@@ -5939,76 +6051,76 @@ class Context(object):
Decimal('7.89E+77')
>>> ExtendedContext.to_integral_value(Decimal('-Inf'))
Decimal('-Infinity')
- """
- a = _convert_other(a, raiseit=True)
- return a.to_integral_value(context=self)
-
- # the method name changed, but we provide also the old one, for compatibility
- to_integral = to_integral_value
-
-class _WorkRep(object):
- __slots__ = ('sign','int','exp')
- # sign: 0 or 1
- # int: int
- # exp: None, int, or string
-
- def __init__(self, value=None):
- if value is None:
- self.sign = None
- self.int = 0
- self.exp = None
- elif isinstance(value, Decimal):
- self.sign = value._sign
- self.int = int(value._int)
- self.exp = value._exp
- else:
- # assert isinstance(value, tuple)
- self.sign = value[0]
- self.int = value[1]
- self.exp = value[2]
-
- def __repr__(self):
- return "(%r, %r, %r)" % (self.sign, self.int, self.exp)
-
- __str__ = __repr__
-
-
-
-def _normalize(op1, op2, prec = 0):
- """Normalizes op1, op2 to have the same exp and length of coefficient.
+ "
+ (let* ((a (_convert_other a #:raiseit #t)))
+ ((ref a 'to_integral_value) #:context self))))
+
+ ;; the method name changed, but we provide also the old one, for compatibility
+ (define to_integral to_integral_value))
+
+(define-python-class _WorkRep ()
+ (define __init__
+ (lam (self (= value None))
+ (cond
+ ((eq? value None)
+ (set self 'sign None)
+ (set self 'int 0)
+ (set self 'exp None))
+ ((isinstance value Decimal)
+ (set self 'sign (ref value '_sign))
+ (set self 'int (int (ref value '_int)))
+ (set self 'exp (ref value '_exp)))
+ (else
+ ;; assert isinstance(value, tuple)
+ (set self 'sign (pylist-ref value 0))
+ (set self 'int (pylist-ref value 1))
+ (set self 'exp (pylist-ref value 2))))))
+
+ (define __repr__
+ (lambda (self)
+ (format "(~a, ~a, ~a)" (ref self 'sign) (ref self 'int) (ref self 'exp))))
+
+ (define __str__ __repr__))
+
+
+
+(define _normalize
+ (lam (op1 op2 (= prec 0))
+ "Normalizes op1, op2 to have the same exp and length of coefficient.
Done during addition.
- """
- if op1.exp < op2.exp:
- tmp = op2
- other = op1
- else:
- tmp = op1
- other = op2
-
- # Let exp = min(tmp.exp - 1, tmp.adjusted() - precision - 1).
- # Then adding 10**exp to tmp has the same effect (after rounding)
- # as adding any positive quantity smaller than 10**exp; similarly
- # for subtraction. So if other is smaller than 10**exp we replace
- # it with 10**exp. This avoids tmp.exp - other.exp getting too large.
- tmp_len = len(str(tmp.int))
- other_len = len(str(other.int))
- exp = tmp.exp + min(-1, tmp_len - prec - 2)
- if other_len + other.exp - 1 < exp:
- other.int = 1
- other.exp = exp
-
- tmp.int *= 10 ** (tmp.exp - other.exp)
- tmp.exp = other.exp
- return op1, op2
-
-
-##### Integer arithmetic functions used by ln, log10, exp and __pow__ #####
-
-_nbits = int.bit_length
-
-def _decimal_lshift_exact(n, e):
- """ Given integers n and e, return n * 10**e if it's an integer, else None.
+ "
+ (call-with-values
+ (lambda ()
+ (if (< (ref op1 'exp) (ref op2 'exp))
+ (values op2 op1)
+ (values op1 op2)))
+ (lambda (tmp other)
+ ;; Let exp = min(tmp.exp - 1, tmp.adjusted() - precision - 1).
+ ;; Then adding 10**exp to tmp has the same effect (after rounding)
+ ;; as adding any positive quantity smaller than 10**exp; similarly
+ ;; for subtraction. So if other is smaller than 10**exp we replace
+ ;; it with 10**exp. This avoids tmp.exp - other.exp getting too large.
+ (let* ((tmp_len (len (str (ref tmp 'int))))
+ (other_len (len (str (ref other 'int))))
+ (exp (+ (ref tmp 'exp)
+ (min -1 (- tmp_len prec 2)))))
+ (when (< (+ other_len (ref other 'exp) -1) exp)
+ (set other 'int 1)
+ (set other 'exp exp))
+
+ (set tmp 'int (* (ref tmp 'int) (expt 10 (- (ref tmp 'exp) (ref other 'exp)))))
+ (set tmp 'exp (ref other 'exp))
+ (values op1 op2))))))
+
+
+;;##### Integer arithmetic functions used by ln, log10, exp and __pow__ #####
+
+(define _nbits (ref int 'bit_length))
+
+(define _decimal_lshift_exact
+ (lambda (n e)
+ " Given integers n and e, return n * 10**e if it's an integer, else None.
The computation is designed to avoid computing large powers of 10
unnecessarily.
@@ -6017,50 +6129,59 @@ def _decimal_lshift_exact(n, e):
30000
>>> _decimal_lshift_exact(300, -999999999) # returns None
- """
- if n == 0:
- return 0
- elif e >= 0:
- return n * 10**e
- else:
- # val_n = largest power of 10 dividing n.
- str_n = str(abs(n))
- val_n = len(str_n) - len(str_n.rstrip('0'))
- return None if val_n < -e else n // 10**-e
-
-def _sqrt_nearest(n, a):
- """Closest integer to the square root of the positive integer n. a is
+ "
+ (cond
+ ((= n 0)
+ 0)
+ ((>= e 0)
+ (* n (expt 10 e)))
+ (else
+ ;; val_n = largest power of 10 dividing n.
+ (let* ((str_n (str (abs n)))
+ (val_n (- (len str_n) (len ((ref str_n 'rstrip) "0")))))
+ (if (< val_n (- e))
+ None
+ (floor-quotient n (expt 10 (- e)))))))))
+
+(define _sqrt_nearest
+ (lambda (n a)
+ "Closest integer to the square root of the positive integer n. a is
an initial approximation to the square root. Any positive integer
will do for a, but the closer a is to the square root of n the
faster convergence will be.
- """
- if n <= 0 or a <= 0:
- raise ValueError("Both arguments to _sqrt_nearest should be positive.")
+ "
+ (if (or (<= n 0) (<= a 0))
+ (raise (ValueError "Both arguments to _sqrt_nearest should be positive.")))
- b=0
- while a != b:
- b, a = a, a--n//a>>1
- return a
+ (let lp ((b 0) (a a))
+ (if (not (= a b))
+ (lp a (ash (- a (floor-quotient (- n) a)) -1))
+ a))))
-def _rshift_nearest(x, shift):
- """Given an integer x and a nonnegative integer shift, return closest
+(define _rshift_nearest
+ (lambda (x shift)
+ "Given an integer x and a nonnegative integer shift, return closest
integer to x / 2**shift; use round-to-even in case of a tie.
- """
- b, q = 1 << shift, x >> shift
- return q + (2*(x & (b-1)) + (q&1) > b)
+ "
+ (let ((b (ash 1 shift))
+ (q (ash x (- shift))))
+ (+ q (if (> (+ (* 2 (logand x (- b 1))) (logand q 1)) b) 1 0)))))
-def _div_nearest(a, b):
- """Closest integer to a/b, a and b positive integers; rounds to even
+(define _div_nearest
+ (lambda (a b)
+ "Closest integer to a/b, a and b positive integers; rounds to even
in the case of a tie.
- """
- q, r = divmod(a, b)
- return q + (2*r + (q&1) > b)
+ "
+ (call-with-values (lambda () (py-divmod a b))
+ (lambda (q r)
+ (+ q (if (> (+ (* 2 r) (logand q 1)) b) 1 0))))))
-def _ilog(x, M, L = 8):
- """Integer approximation to M*log(x/M), with absolute error boundable
+(define _ilog
+ (lambda (x M (= L 8))
+ "Integer approximation to M*log(x/M), with absolute error boundable
in terms only of x/M.
Given positive integers x and M, return an integer approximation to
@@ -6068,199 +6189,208 @@ def _ilog(x, M, L = 8):
between the approximation and the exact result is at most 22. For
L = 8 and 1.0 <= x/M <= 10.0 the difference is at most 15. In
both cases these are upper bounds on the error; it will usually be
- much smaller."""
+ much smaller."
- # The basic algorithm is the following: let log1p be the function
- # log1p(x) = log(1+x). Then log(x/M) = log1p((x-M)/M). We use
- # the reduction
- #
- # log1p(y) = 2*log1p(y/(1+sqrt(1+y)))
- #
- # repeatedly until the argument to log1p is small (< 2**-L in
- # absolute value). For small y we can use the Taylor series
- # expansion
- #
- # log1p(y) ~ y - y**2/2 + y**3/3 - ... - (-y)**T/T
- #
- # truncating at T such that y**T is small enough. The whole
- # computation is carried out in a form of fixed-point arithmetic,
- # with a real number z being represented by an integer
- # approximation to z*M. To avoid loss of precision, the y below
- # is actually an integer approximation to 2**R*y*M, where R is the
- # number of reductions performed so far.
-
- y = x-M
- # argument reduction; R = number of reductions performed
- R = 0
- while (R <= L and abs(y) << L-R >= M or
- R > L and abs(y) >> R-L >= M):
- y = _div_nearest((M*y) << 1,
- M + _sqrt_nearest(M*(M+_rshift_nearest(y, R)), M))
- R += 1
-
- # Taylor series with T terms
- T = -int(-10*len(str(M))//(3*L))
- yshift = _rshift_nearest(y, R)
- w = _div_nearest(M, T)
- for k in range(T-1, 0, -1):
- w = _div_nearest(M, k) - _div_nearest(yshift*w, M)
-
- return _div_nearest(w*y, M)
-
-def _dlog10(c, e, p):
- """Given integers c, e and p with c > 0, p >= 0, compute an integer
+ ;; The basic algorithm is the following: let log1p be the function
+ ;; log1p(x) = log(1+x). Then log(x/M) = log1p((x-M)/M). We use
+ ;; the reduction
+ ;;
+ ;; log1p(y) = 2*log1p(y/(1+sqrt(1+y)))
+ ;;
+ ;; repeatedly until the argument to log1p is small (< 2**-L in
+ ;; absolute value). For small y we can use the Taylor series
+ ;; expansion
+ ;;
+ ;; log1p(y) ~ y - y**2/2 + y**3/3 - ... - (-y)**T/T
+ ;;
+ ;; truncating at T such that y**T is small enough. The whole
+ ;; computation is carried out in a form of fixed-point arithmetic,
+ ;; with a real number z being represented by an integer
+ ;; approximation to z*M. To avoid loss of precision, the y below
+ ;; is actually an integer approximation to 2**R*y*M, where R is the
+ ;; number of reductions performed so far.
+
+ ;; argument reduction; R = number of reductions performed
+ (call-with-values
+ (lambda ()
+ (let lp ((y (- x M)) (R 0))
+ (if (>= (ash (abs y) (- L R)) M)
+ (values
+ (_div_nearest (ash (* M y) 1)
+ (+ M (_sqrt_nearest (* M (+ M (_rshift_nearest y R))) M)))
+ (+ R 1))
+ (values y R))))
+ (lambda (y R)
+ ;; Taylor series with T terms
+ (let* ((T (- (int (* -10 (floor-quotient (len (str M)) (* 3 L))))))
+ (yshift (_rshift_nearest y R))
+ (w (_div_nearest M T)))
+ (for ((k : (range (- T 1) 0 -1))) ((w w))
+ (- (_div_nearest M k) (_div_nearest (* yshift w M)))
+ #:final
+ (_div_nearest (* w y) M)))))))
+
+(define _dlog10
+ (lambda (c e p)
+ "Given integers c, e and p with c > 0, p >= 0, compute an integer
approximation to 10**p * log10(c*10**e), with an absolute error of
- at most 1. Assumes that c*10**e is not exactly 1."""
-
- # increase precision by 2; compensate for this by dividing
- # final result by 100
- p += 2
-
- # write c*10**e as d*10**f with either:
- # f >= 0 and 1 <= d <= 10, or
- # f <= 0 and 0.1 <= d <= 1.
- # Thus for c*10**e close to 1, f = 0
- l = len(str(c))
- f = e+l - (e+l >= 1)
-
- if p > 0:
- M = 10**p
- k = e+p-f
- if k >= 0:
- c *= 10**k
- else:
- c = _div_nearest(c, 10**-k)
-
- log_d = _ilog(c, M) # error < 5 + 22 = 27
- log_10 = _log10_digits(p) # error < 1
- log_d = _div_nearest(log_d*M, log_10)
- log_tenpower = f*M # exact
- else:
- log_d = 0 # error < 2.31
- log_tenpower = _div_nearest(f, 10**-p) # error < 0.5
-
- return _div_nearest(log_tenpower+log_d, 100)
-
-def _dlog(c, e, p):
- """Given integers c, e and p with c > 0, compute an integer
+ at most 1. Assumes that c*10**e is not exactly 1."
+
+ ;; increase precision by 2; compensate for this by dividing
+ ;; final result by 100
+ (set! p (+ p 2))
+
+ ;; write c*10**e as d*10**f with either:
+ ;; f >= 0 and 1 <= d <= 10, or
+ ;; f <= 0 and 0.1 <= d <= 1.
+ ;; Thus for c*10**e close to 1, f = 0
+ (call-with-values
+ (lambda ()
+ (let* ((l (len (str c)))
+ (f (- (+ e l) (if (>= (+ e l) 1) 1 0))))
+ (if (> p 0)
+ (let* ((M (expt 10 p))
+ (k (- (+ e p) f))
+ (c (if (>= k 0)
+ (* c (expt 10 k))
+ (_div_nearest c (expt 10 (- k)))))
+ (log_d (_ilog c M)) ;; error < 5 + 22 = 27
+ (log_10 (_log10_digits p))) ;; error < 1
+ (values (_div_nearest (* log_d M) log_10)
+ (* f M))) ;; exact
+ (values 0 ;; error < 2.31
+ (_div_nearest f (expt 10 (- p))))))) ;; error < 0.5
+ (lambda (log_d log_tenpower)
+ (_div_nearest (+ log_tenpower log_d) 100)))))
+
+(define _dlog
+ (lambda (c e p)
+ "Given integers c, e and p with c > 0, compute an integer
approximation to 10**p * log(c*10**e), with an absolute error of
- at most 1. Assumes that c*10**e is not exactly 1."""
-
- # Increase precision by 2. The precision increase is compensated
- # for at the end with a division by 100.
- p += 2
-
- # rewrite c*10**e as d*10**f with either f >= 0 and 1 <= d <= 10,
- # or f <= 0 and 0.1 <= d <= 1. Then we can compute 10**p * log(c*10**e)
- # as 10**p * log(d) + 10**p*f * log(10).
- l = len(str(c))
- f = e+l - (e+l >= 1)
-
- # compute approximation to 10**p*log(d), with error < 27
- if p > 0:
- k = e+p-f
- if k >= 0:
- c *= 10**k
- else:
- c = _div_nearest(c, 10**-k) # error of <= 0.5 in c
-
- # _ilog magnifies existing error in c by a factor of at most 10
- log_d = _ilog(c, 10**p) # error < 5 + 22 = 27
- else:
- # p <= 0: just approximate the whole thing by 0; error < 2.31
- log_d = 0
-
- # compute approximation to f*10**p*log(10), with error < 11.
- if f:
- extra = len(str(abs(f)))-1
- if p + extra >= 0:
- # error in f * _log10_digits(p+extra) < |f| * 1 = |f|
- # after division, error < |f|/10**extra + 0.5 < 10 + 0.5 < 11
- f_log_ten = _div_nearest(f*_log10_digits(p+extra), 10**extra)
- else:
- f_log_ten = 0
- else:
- f_log_ten = 0
-
- # error in sum < 11+27 = 38; error after division < 0.38 + 0.5 < 1
- return _div_nearest(f_log_ten + log_d, 100)
-
-class _Log10Memoize(object):
- """Class to compute, store, and allow retrieval of, digits of the
+ at most 1. Assumes that c*10**e is not exactly 1."
+
+ ;; Increase precision by 2. The precision increase is compensated
+ ;; for at the end with a division by 100.
+ (set! p (+ p 2))
+
+ ;; rewrite c*10**e as d*10**f with either f >= 0 and 1 <= d <= 10,
+ ;; or f <= 0 and 0.1 <= d <= 1. Then we can compute 10**p * log(c*10**e)
+ ;; as 10**p * log(d) + 10**p*f * log(10).
+ (let* ((l (len (str c)))
+ (f (- (+ e l) (if (>= (+ e l) 1) 1 0))))
+
+ ;; compute approximation to 10**p*log(d), with error < 27
+ (call-with-values
+ (lambda ()
+ (if (> p 0)
+ (let* ((k (- (+ e p) f))
+ (c (if (>= k 0)
+ (* c (expt 10 k))
+ (_div_nearest c (expt 10 (- k)))))) ; error of <= 0.5 in c
+
+ ;; _ilog magnifies existing error in c by a factor of at most 10
+ (_ilog c, (expt 10 p))) ; error < 5 + 22 = 27
+ ;; p <= 0: just approximate the whole thing by 0; error < 2.31
+ 0))
+ (lambda (log_d)
+ (call-with-values
+ (lambda ()
+ ;; compute approximation to f*10**p*log(10), with error < 11.
+ (if (not (= f 0))
+ (let ((extra (- (len (str (abs f))) 1)))
+ (if (>= (+ p extra) 0)
+ ;; error in f * _log10_digits(p+extra) < |f| * 1 = |f|
+ ;; after division, error < |f|/10**extra + 0.5 < 10 + 0.5 < 11
+ (_div_nearest (* f (_log10_digits (+ p extra))) (expt 10 extra))
+ 0))
+ 0))
+ (lambda (f_log_ten)
+ ;; error in sum < 11+27 = 38; error after division < 0.38 + 0.5 < 1
+ (_div_nearest (+ f_log_ten log_d) 100))))))))
+
+(define-python-class _Log10Memoize ()
+ "Class to compute, store, and allow retrieval of, digits of the
constant log(10) = 2.302585.... This constant is needed by
- Decimal.ln, Decimal.log10, Decimal.exp and Decimal.__pow__."""
- def __init__(self):
- self.digits = "23025850929940456840179914546843642076011014886"
+ Decimal.ln, Decimal.log10, Decimal.exp and Decimal.__pow__."
+
+ (define __init__
+ (lambda (self)
+ (set self 'digits "23025850929940456840179914546843642076011014886")))
- def getdigits(self, p):
- """Given an integer p >= 0, return floor(10**p)*log(10).
+ (define getdigits
+ (lambda (self p)
+ "Given an integer p >= 0, return floor(10**p)*log(10).
For example, self.getdigits(3) returns 2302.
- """
- # digits are stored as a string, for quick conversion to
- # integer in the case that we've already computed enough
- # digits; the stored digits should always be correct
- # (truncated, not rounded to nearest).
- if p < 0:
- raise ValueError("p should be nonnegative")
-
- if p >= len(self.digits):
- # compute p+3, p+6, p+9, ... digits; continue until at
- # least one of the extra digits is nonzero
- extra = 3
- while True:
- # compute p+extra digits, correct to within 1ulp
- M = 10**(p+extra+2)
- digits = str(_div_nearest(_ilog(10*M, M), 100))
- if digits[-extra:] != '0'*extra:
- break
- extra += 3
- # keep all reliable digits so far; remove trailing zeros
- # and next nonzero digit
- self.digits = digits.rstrip('0')[:-1]
- return int(self.digits[:p+1])
-
-_log10_digits = _Log10Memoize().getdigits
-
-def _iexp(x, M, L=8):
- """Given integers x and M, M > 0, such that x/M is small in absolute
- value, compute an integer approximation to M*exp(x/M). For 0 <=
- x/M <= 2.4, the absolute error in the result is bounded by 60 (and
- is usually much smaller)."""
-
- # Algorithm: to compute exp(z) for a real number z, first divide z
- # by a suitable power R of 2 so that |z/2**R| < 2**-L. Then
- # compute expm1(z/2**R) = exp(z/2**R) - 1 using the usual Taylor
- # series
- #
- # expm1(x) = x + x**2/2! + x**3/3! + ...
- #
- # Now use the identity
- #
- # expm1(2x) = expm1(x)*(expm1(x)+2)
- #
- # R times to compute the sequence expm1(z/2**R),
- # expm1(z/2**(R-1)), ... , exp(z/2), exp(z).
-
- # Find R such that x/2**R/M <= 2**-L
- R = _nbits((x<<L)//M)
-
- # Taylor series. (2**L)**T > M
- T = -int(-10*len(str(M))//(3*L))
- y = _div_nearest(x, T)
- Mshift = M<<R
- for i in range(T-1, 0, -1):
- y = _div_nearest(x*(Mshift + y), Mshift * i)
+ "
+ ;; digits are stored as a string, for quick conversion to
+ ;; integer in the case that we've already computed enough
+ ;; digits; the stored digits should always be correct
+ ;; (truncated, not rounded to nearest).
+ (if (< p 0) (raise (ValueError "p should be nonnegative")))
+
+ (if (>= p (len (ref self 'digits)))
+ ;; compute p+3, p+6, p+9, ... digits; continue until at
+ ;; least one of the extra digits is nonzero
+ (begin
+ (let lp ((extra 3))
+ ;; compute p+extra digits, correct to within 1ulp
+ (let* ((M (expt 10 (+ p extra 2)))
+ (digits (str (_div_nearest (_ilog (* 10 M), M) 100))))
+ (if (not (equal? (pylist-slice digits (- extra) None None)
+ (* '0' extra)))
+ #t
+ (lp (+ extra 3))))))
+ ;; keep all reliable digits so far; remove trailing zeros
+ ;; and next nonzero digit
+ (set self 'digits (pylist-slice ((ref digits 'rstrip) "0") None -1 None)))
+
+ (int (pylist-slice (ref self 'digits) None (+ p 1) None)))))
- # Expansion
- for k in range(R-1, -1, -1):
- Mshift = M<<(k+2)
- y = _div_nearest(y*(y+Mshift), Mshift)
+(define _log10_digits (ref (_Log10Memoize) 'getdigits))
- return M+y
+(define _iexp
+ (lam (x M (= L 8))
+ "Given integers x and M, M > 0, such that x/M is small in absolute
+ value, compute an integer approximation to M*exp(x/M). For 0 <=
+ x/M <= 2.4, the absolute error in the result is bounded by 60 (and
+ is usually much smaller)."
-def _dexp(c, e, p):
- """Compute an approximation to exp(c*10**e), with p decimal places of
+ ;; Algorithm: to compute exp(z) for a real number z, first divide z
+ ;; by a suitable power R of 2 so that |z/2**R| < 2**-L. Then
+ ;; compute expm1(z/2**R) = exp(z/2**R) - 1 using the usual Taylor
+ ;; series
+ ;;
+ ;; expm1(x) = x + x**2/2! + x**3/3! + ...
+ ;;
+ ;; Now use the identity
+ ;;
+ ;; expm1(2x) = expm1(x)*(expm1(x)+2)
+ ;;
+ ;; R times to compute the sequence expm1(z/2**R),
+ ;; expm1(z/2**(R-1)), ... , exp(z/2), exp(z).
+
+ ;; Find R such that x/2**R/M <= 2**-L
+ (let ((R (_nbits (floor-quotient (ash x L) M))))
+ ;; Taylor series. (2**L)**T > M
+ (let* ((T (- (int (floor-quotient (* -10 (len( strM))) (* 3 L)))))
+ (y1 (let ((Mshift (ash M R)))
+ (for ((i : (range (- T1) 0 -1))) ((y (_div_nearest x T)))
+ (_div_nearest (* x (+ Mshift y)) (* Mshift i))
+ #:final y)))
+
+
+ ;; Expansion
+ (y2 (for ((k : (range (- R 1) -1 -1))) ((y y1))
+ (let ((Mshift (ash M (+ k 2))))
+ (_div_nearest (* y (+ y Mshift)) Mshift))
+ #:final y)))
+
+ (+ M y2)))))
+
+(define _dexp
+ (lambda (c e p)
+ "Compute an approximation to exp(c*10**e), with p decimal places of
precision.
Returns integers d, f such that:
@@ -6271,32 +6401,35 @@ def _dexp(c, e, p):
In other words, d*10**f is an approximation to exp(c*10**e) with p
digits of precision, and with an error in d of at most 1. This is
almost, but not quite, the same as the error being < 1ulp: when d
- = 10**(p-1) the error could be up to 10 ulp."""
-
- # we'll call iexp with M = 10**(p+2), giving p+3 digits of precision
- p += 2
-
- # compute log(10) with extra precision = adjusted exponent of c*10**e
- extra = max(0, e + len(str(c)) - 1)
- q = p + extra
-
- # compute quotient c*10**e/(log(10)) = c*10**(e+q)/(log(10)*10**q),
- # rounding down
- shift = e+q
- if shift >= 0:
- cshift = c*10**shift
- else:
- cshift = c//10**-shift
- quot, rem = divmod(cshift, _log10_digits(q))
+ = 10**(p-1) the error could be up to 10 ulp."
- # reduce remainder back to original precision
- rem = _div_nearest(rem, 10**extra)
+ ;; we'll call iexp with M = 10**(p+2), giving p+3 digits of precision
+ (set! p (+ p 2))
- # error in result of _iexp < 120; error after division < 0.62
- return _div_nearest(_iexp(rem, 10**p), 1000), quot - p + 3
+ ;; compute log(10) with extra precision = adjusted exponent of c*10**e
+ (let* ((extra (max 0 (+ e (len (str c)) -1)))
+ (q (+ p extra)))
-def _dpower(xc, xe, yc, ye, p):
- """Given integers xc, xe, yc and ye representing Decimals x = xc*10**xe and
+ ;; compute quotient c*10**e/(log(10)) = c*10**(e+q)/(log(10)*10**q),
+ ;; rounding down
+ (let* ((shift (+ e q))
+ (cshift (if (>= shift 0)
+ (* c (expt 10 shift))
+ (floor-quotient c (expt 10 (- shift))))))
+ (call-with-values
+ (lambda ()
+ (divmod cshift (_log10_digits q)))
+ (lambda (quot rem)
+ ;; reduce remainder back to original precision
+ (set! rem (_div_nearest rem (expt 10 extra)))
+
+ ;; error in result of _iexp < 120; error after division < 0.62
+ (values (_div_nearest (_iexp rem (expt 10 p)) 1000)
+ (+ quot (- p) 3))))))))
+
+(define _dpower
+ (lambda (xc xe yc ye p)
+ "Given integers xc, xe, yc and ye representing Decimals x = xc*10**xe and
y = yc*10**ye, compute x**y. Returns a pair of integers (c, e) such that:
10**(p-1) <= c <= 10**p, and
@@ -6308,182 +6441,198 @@ def _dpower(xc, xe, yc, ye, p):
== 10**(p-1) we can only guarantee error < 10ulp.)
We assume that: x is positive and not equal to 1, and y is nonzero.
- """
-
- # Find b such that 10**(b-1) <= |y| <= 10**b
- b = len(str(abs(yc))) + ye
-
- # log(x) = lxc*10**(-p-b-1), to p+b+1 places after the decimal point
- lxc = _dlog(xc, xe, p+b+1)
-
- # compute product y*log(x) = yc*lxc*10**(-p-b-1+ye) = pc*10**(-p-1)
- shift = ye-b
- if shift >= 0:
- pc = lxc*yc*10**shift
- else:
- pc = _div_nearest(lxc*yc, 10**-shift)
-
- if pc == 0:
- # we prefer a result that isn't exactly 1; this makes it
- # easier to compute a correctly rounded result in __pow__
- if ((len(str(xc)) + xe >= 1) == (yc > 0)): # if x**y > 1:
- coeff, exp = 10**(p-1)+1, 1-p
- else:
- coeff, exp = 10**p-1, -p
- else:
- coeff, exp = _dexp(pc, -(p+1), p+1)
- coeff = _div_nearest(coeff, 10)
- exp += 1
-
- return coeff, exp
-
-def _log10_lb(c, correction = {
- '1': 100, '2': 70, '3': 53, '4': 40, '5': 31,
- '6': 23, '7': 16, '8': 10, '9': 5}):
- """Compute a lower bound for 100*log10(c) for a positive integer c."""
- if c <= 0:
- raise ValueError("The argument to _log10_lb should be nonnegative.")
- str_c = str(c)
- return 100*len(str_c) - correction[str_c[0]]
-
-##### Helper Functions ####################################################
+ "
-def _convert_other(other, raiseit=False, allow_float=False):
- """Convert other to Decimal.
+ (let*
+ ;; Find b such that 10**(b-1) <= |y| <= 10**b
+ ((b (+ (len (str (abs yc))) ye))
+
+ ;; log(x) = lxc*10**(-p-b-1), to p+b+1 places after the decimal point
+ (lxc (_dlog xc xe (+ p b 1)))
+
+ ;; compute product y*log(x) = yc*lxc*10**(-p-b-1+ye) = pc*10**(-p-1)
+ (shift (- ye b))
+ (ps (if (>= shift 0)
+ (* lxc yc (expt 10 shift))
+ (_div_nearest (* lxc yc) (expt 10 (- shift))))))
+
+ (if (= pc 0)
+ ;; we prefer a result that isn't exactly 1; this makes it
+ ;; easier to compute a correctly rounded result in __pow__
+ (if (eq? (>= (+ (len (str xc)) xe) 1)
+ (> yc 0)) ; if x**y > 1:
+ (values (+ (expt 10 (- p1)) 1) (- 1 p))
+ (values (- (expt 10 p) 1) (- p)))
+ (call-with-values
+ (lambda ()
+ (_dexp pc (- (+ p1)) (+ p 1)))
+ (lambda (coeff exp)
+ (values (_div_nearest coeff 10)
+ (+ exp 1))))))))
+
+(define _corr (dict '(("1" . 100) ("2" . 70) ("3" . 53) ("4" . 40) ("5" . 31)
+ ("6" . 23 ) ("7" . 16) ("8" . 10) ("9" . 5))))
+(define _log10_lb
+ (lam (c (= correction _corr))
+ "Compute a lower bound for 100*log10(c) for a positive integer c."
+ (if (<= c 0)
+ (raise (ValueError "The argument to _log10_lb should be nonnegative.")))
+ (let ((str_c (str c)))
+ (- (* 100 (len str_c) (pylist-ref correction (pylist-ref str_c 0)))))))
+
+;;#### Helper Functions ####################################################
+
+(define _convert_other
+ (lam (other (= raiseit #f) (= allow_float #f))
+ "Convert other to Decimal.
Verifies that it's ok to use in an implicit construction.
If allow_float is true, allow conversion from float; this
is used in the comparison methods (__eq__ and friends).
- """
- if isinstance(other, Decimal):
- return other
- if isinstance(other, int):
- return Decimal(other)
- if allow_float and isinstance(other, float):
- return Decimal.from_float(other)
-
- if raiseit:
- raise TypeError("Unable to convert %s to Decimal" % other)
- return NotImplemented
-
-def _convert_for_comparison(self, other, equality_op=False):
- """Given a Decimal instance self and a Python object other, return
- a pair (s, o) of Decimal instances such that "s op o" is
- equivalent to "self op other" for any of the 6 comparison
- operators "op".
+ "
+ (cond
+ ((isinstance other Decimal)
+ other)
+ ((isinstance other int)
+ (Decimal other))
+ ((and allow_float (isinstance other float))
+ ((ref Decimal 'from_float) other))
+ (raiseit
+ (raise (TypeError (format #f "Unable to convert ~a to Decimal" other))))
+ (else
+ NotImplemented))))
+
+(define _convert_for_comparison
+ (lam (self other (= equality_op #f))
+ "Given a Decimal instance self and a Python object other, return
+ a pair (s, o) of Decimal instances such that 's op o' is
+ equivalent to 'self op other' for any of the 6 comparison
+ operators 'op'.
- """
- if isinstance(other, Decimal):
- return self, other
-
- # Comparison with a Rational instance (also includes integers):
- # self op n/d <=> self*d op n (for n and d integers, d positive).
- # A NaN or infinity can be left unchanged without affecting the
- # comparison result.
- if isinstance(other, _numbers.Rational):
- if not self._is_special:
- self = _dec_from_triple(self._sign,
- str(int(self._int) * other.denominator),
- self._exp)
- return self, Decimal(other.numerator)
-
- # Comparisons with float and complex types. == and != comparisons
- # with complex numbers should succeed, returning either True or False
- # as appropriate. Other comparisons return NotImplemented.
- if equality_op and isinstance(other, _numbers.Complex) and other.imag == 0:
- other = other.real
- if isinstance(other, float):
- context = getcontext()
- if equality_op:
- context.flags[FloatOperation] = 1
- else:
- context._raise_error(FloatOperation,
- "strict semantics for mixing floats and Decimals are enabled")
- return self, Decimal.from_float(other)
- return NotImplemented, NotImplemented
-
-
-##### Setup Specific Contexts ############################################
-
-# The default context prototype used by Context()
-# Is mutable, so that new contexts can have different default values
-
-DefaultContext = Context(
- prec=28, rounding=ROUND_HALF_EVEN,
- traps=[DivisionByZero, Overflow, InvalidOperation],
- flags=[],
- Emax=999999,
- Emin=-999999,
- capitals=1,
- clamp=0
-)
-
-# Pre-made alternate contexts offered by the specification
-# Don't change these; the user should be able to select these
-# contexts and be able to reproduce results from other implementations
-# of the spec.
-
-BasicContext = Context(
- prec=9, rounding=ROUND_HALF_UP,
- traps=[DivisionByZero, Overflow, InvalidOperation, Clamped, Underflow],
- flags=[],
-)
-
-ExtendedContext = Context(
- prec=9, rounding=ROUND_HALF_EVEN,
- traps=[],
- flags=[],
-)
-
-
-##### crud for parsing strings #############################################
-#
-# Regular expression used for parsing numeric strings. Additional
-# comments:
-#
-# 1. Uncomment the two '\s*' lines to allow leading and/or trailing
-# whitespace. But note that the specification disallows whitespace in
-# a numeric string.
-#
-# 2. For finite numbers (not infinities and NaNs) the body of the
-# number between the optional sign and the optional exponent must have
-# at least one decimal digit, possibly after the decimal point. The
-# lookahead expression '(?=\d|\.\d)' checks this.
-
-import re
-_parser = re.compile(r""" # A numeric string consists of:
-# \s*
+ "
+ (cond
+ ((isinstance other Decimal)
+ (values self other))
+
+ ;; Comparison with a Rational instance (also includes integers):
+ ;; self op n/d <=> self*d op n (for n and d integers, d positive).
+ ;; A NaN or infinity can be left unchanged without affecting the
+ ;; comparison result.
+ ((isinstance other (ref _numbers Rational))
+ (if (not (bool (ref self '_is_special)))
+ (values
+ (_dec_from_triple (ref self '_sign)
+ (* (str int (ref self '_int)) (ref other 'denominator))
+ (ref self '_exp))
+ (Decimal (ref other 'numerator)))
+ (values NotImplemented NotImplemented)))
+
+ ;; Comparisons with float and complex types. == and != comparisons
+ ;; with complex numbers should succeed, returning either True or False
+ ;; as appropriate. Other comparisons return NotImplemented.
+ (else
+ (let ((other (if (and equality_op
+ (isinstance other (ref_numbers 'Complex))
+ (= (ref other 'imag) 0))
+ (ref other 'real)
+ other)))
+ (if (isinstance other float)
+ (let ((context (getcontext)))
+ (if equality_op
+ (pylist-set! (ref context 'flags) FloatOperation 1)
+ (ctx-error context FloatOperation
+ "strict semantics for mixing floats and Decimals are enabled"))
+ (values self ((ref Decimal 'from_float) other)))
+ (values NotImplemented NotImplemented)))))))
+
+
+;;##### Setup Specific Contexts ############################################
+
+;; The default context prototype used by Context()
+;; Is mutable, so that new contexts can have different default values
+
+(define DefaultContext
+ (Context
+ #:prec 28
+ #:rounding ROUND_HALF_EVEN
+ #:traps (list DivisionByZero Overflow InvalidOperation)
+ #:flags '()
+ #:Emax 999999
+ #:Emin -999999
+ #:capitals 1
+ #:clamp 0))
+
+;; Pre-made alternate contexts offered by the specification
+;; Don't change these; the user should be able to select these
+;; contexts and be able to reproduce results from other implementations
+;; of the spec.
+
+(define BasicContext
+ (Context
+ #:prec 9
+ #:rounding ROUND_HALF_UP
+ #:traps (list DivisionByZero Overflow InvalidOperation Clamped Underflow)
+ #:flags '()))
+
+(define ExtendedContext
+ (Context
+ #:prec 9
+ #:rounding ROUND_HALF_EVEN
+ #:traps '()
+ #:flags '()))
+
+;;##### crud for parsing strings #############################################
+;;#
+;;# Regular expression used for parsing numeric strings. Additional
+;;# comments:
+;;#
+;;# 1. Uncomment the two '\s*' lines to allow leading and/or trailing
+;;# whitespace. But note that the specification disallows whitespace in
+;;# a numeric string.
+;;#
+;;# 2. For finite numbers (not infinities and NaNs) the body of the
+;;# number between the optional sign and the optional exponent must have
+;;# at least one decimal digit, possibly after the decimal point. The
+;;# lookahead expression '(?=\d|\.\d)' checks this.
+
+(use-modules (languge python module re))
+(define _parser
+ (ref
+ (compile " # A numeric string consists of:
+# \\s*
(?P<sign>[-+])? # an optional sign, followed by either...
(
- (?=\d|\.\d) # ...a number (with at least one digit)
- (?P<int>\d*) # having a (possibly empty) integer part
- (\.(?P<frac>\d*))? # followed by an optional fractional part
- (E(?P<exp>[-+]?\d+))? # followed by an optional exponent, or...
+ (?=\\d|\\.\\d) # ...a number (with at least one digit)
+ (?P<int>\\d*) # having a (possibly empty) integer part
+ (\.(?P<frac>\\d*))? # followed by an optional fractional part
+ (E(?P<exp>[-+]?\\d+))? # followed by an optional exponent, or...
|
Inf(inity)? # ...an infinity, or...
|
(?P<signal>s)? # ...an (optionally signaling)
NaN # NaN
- (?P<diag>\d*) # with (possibly empty) diagnostic info.
+ (?P<diag>\\d*) # with (possibly empty) diagnostic info.
)
-# \s*
- \Z
-""", re.VERBOSE | re.IGNORECASE).match
-
-_all_zeros = re.compile('0*$').match
-_exact_half = re.compile('50*$').match
-
-##### PEP3101 support functions ##############################################
-# The functions in this section have little to do with the Decimal
-# class, and could potentially be reused or adapted for other pure
-# Python numeric classes that want to implement __format__
-#
-# A format specifier for Decimal looks like:
-#
-# [[fill]align][sign][#][0][minimumwidth][,][.precision][type]
-
-_parse_format_specifier_regex = re.compile(r"""\A
+# \\s*
+ \\Z
+" (logior VERBOSE IGNORECASE))
+ 'match))
+
+(define _all_zeros (ref (compile "0*$" ) 'match))
+(define _exact_half (ref (compile "50*$") 'match))
+
+;;##### PEP3101 support functions ##############################################
+;;# The functions in this section have little to do with the Decimal
+;;# class, and could potentially be reused or adapted for other pure
+;;# Python numeric classes that want to implement __format__
+;;#
+;;# A format specifier for Decimal looks like:
+;;#
+;;# [[fill]align][sign][#][0][minimumwidth][,][.precision][type]
+
+(define _parse_format_specifier_regex
+ (compile "\\A
(?:
(?P<fill>.)?
(?P<align>[<>=^])
@@ -6491,22 +6640,17 @@ _parse_format_specifier_regex = re.compile(r"""\A
(?P<sign>[-+ ])?
(?P<alt>\#)?
(?P<zeropad>0)?
-(?P<minimumwidth>(?!0)\d+)?
+(?P<minimumwidth>(?!0)\\d+)?
(?P<thousands_sep>,)?
-(?:\.(?P<precision>0|(?!0)\d+))?
+(?:\.(?P<precision>0|(?!0)\\d+))?
(?P<type>[eEfFgGn%])?
-\Z
-""", re.VERBOSE|re.DOTALL)
-
-del re
+\\Z
+" (logior VERBOSE DOTALL)))
-# The locale module is only needed for the 'n' format specifier. The
-# rest of the PEP 3101 code functions quite happily without it, so we
-# don't care too much if locale isn't present.
-try:
- import locale as _locale
-except ImportError:
- pass
+;; The locale module is only needed for the 'n' format specifier. The
+;; rest of the PEP 3101 code functions quite happily without it, so we
+;; don't care too much if locale isn't present.
+(define _locale (import "locale"))
def _parse_format_specifier(format_spec, _localeconv=None):
"""Parse and validate a format specifier.
@@ -6723,26 +6867,27 @@ def _format_number(is_negative, intpart, fracpart, exp, spec):
return _format_align(sign, intpart+fracpart, spec)
-##### Useful Constants (internal use only) ################################
+;;##### Useful Constants (internal use only) ################################
+
+;; Reusable defaults
+(define _Infinity (Decimal "Inf"))
+(define _NegativeInfinity (Decimal "-Inf"))
+(define _NaN (Decimal "NaN"))
+(define _Zero (Decimal 0))
+(define _One (Decimal 1))
+(define _NegativeOne (Decimal -1))
+
+;; _SignedInfinity[sign] is infinity w/ that sign
+(define _SignedInfinity (list _Infinity _NegativeInfinity))
-# Reusable defaults
-_Infinity = Decimal('Inf')
-_NegativeInfinity = Decimal('-Inf')
-_NaN = Decimal('NaN')
-_Zero = Decimal(0)
-_One = Decimal(1)
-_NegativeOne = Decimal(-1)
+;; Constants related to the hash implementation; hash(x) is based
+;; on the reduction of x modulo _PyHASH_MODULUS
+(define _PyHASH_MODULUS (ref hash_info 'modulus))
-# _SignedInfinity[sign] is infinity w/ that sign
-_SignedInfinity = (_Infinity, _NegativeInfinity)
+;; hash values to use for positive and negative infinities, and nans
+(define _PyHASH_INF (ref hash_info 'inf))
+(define _PyHASH_NAN (ref hash_info 'nan))
-# Constants related to the hash implementation; hash(x) is based
-# on the reduction of x modulo _PyHASH_MODULUS
-_PyHASH_MODULUS = sys.hash_info.modulus
-# hash values to use for positive and negative infinities, and nans
-_PyHASH_INF = sys.hash_info.inf
-_PyHASH_NAN = sys.hash_info.nan
+;; _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
+(define _PyHASH_10INV (py-pow 10 (- _PyHASH_MODULUS 2) _PyHASH_MODULUS))
-# _PyHASH_10INV is the inverse of 10 modulo the prime _PyHASH_MODULUS
-_PyHASH_10INV = pow(10, _PyHASH_MODULUS - 2, _PyHASH_MODULUS)
-del sys