From 571e579fac804af51bc5e3f8751415793c367213 Mon Sep 17 00:00:00 2001 From: Stefan Krah Date: Fri, 21 Feb 2020 15:17:54 +0100 Subject: [PATCH 1/2] bpo-39576: Explain the role of the context in decimal arbitrary precision arithmetic. --- Doc/library/decimal.rst | 66 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index bcae55eb821784..41d27de2d73422 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -2121,17 +2121,67 @@ Q. Is the CPython implementation fast for large numbers? A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of the decimal module integrate the high speed `libmpdec `_ library for -arbitrary precision correctly-rounded decimal floating point arithmetic. +arbitrary precision correctly-rounded decimal floating point arithmetic [#]_. ``libmpdec`` uses `Karatsuba multiplication `_ for medium-sized numbers and the `Number Theoretic Transform `_ -for very large numbers. However, to realize this performance gain, the -context needs to be set for unrounded calculations. +for very large numbers. - >>> c = getcontext() - >>> c.prec = MAX_PREC - >>> c.Emax = MAX_EMAX - >>> c.Emin = MIN_EMIN +The context must be adapted for exact arbitrary precision arithmetic. :attr:`Emin` +and :attr:`Emax` should always be set to the maximum values, :attr:`clamp` +should always be `0` (the default). Setting :attr:`prec` requires some care. -.. versionadded:: 3.3 \ No newline at end of file +The easiest approach for trying out bignum arithmetic is to use the maximum +value for :attr:`prec` as well [#]_:: + + >>> setcontext(Context(prec=MAX_PREC, Emax=MAX_EMAX, Emin=MIN_EMIN)) + >>> x = Decimal(2) ** 256 + >>> x / 128 + Decimal('904625697166532776746648320380374280103671755200316906558262375061821325312') + + +For inexact results, :attr:`MAX_PREC` is far too large on 64-bit platforms and +the available memory will be insufficient:: + + >>> Decimal(1) / 3 + Traceback (most recent call last): + File "", line 1, in + MemoryError + +On systems with overallocation (e.g. Linux), a more sophisticated approach is to +adjust :attr:`prec` to the amount of available RAM. Suppose that you have 8GB of +RAM and expect 10 simultaneous operands using a maximum of 500MB each:: + + >>> import sys + >>> + >>> # Maximum number of digits for a single operand using 500MB in 8 byte words + >>> # with 19 (9 for the 32-bit version) digits per word: + >>> maxdigits = 19 * ((500 * 1024**2) // 8) + >>> + >>> # Check that this works: + >>> c = Context(prec=maxdigits, Emax=MAX_EMAX, Emin=MIN_EMIN) + >>> c.traps[Inexact] = True + >>> setcontext(c) + >>> + >>> # Fill the available precision with nines: + >>> x = Decimal(0).logical_invert() * 9 + >>> sys.getsizeof(x) + 524288112 + >>> x + 2 + Traceback (most recent call last): + File "", line 1, in + decimal.Inexact: [] + +In general (and especially on systems without overallocation), it is recommended +to estimate even tighter bounds and set the :attr:`Inexact` trap if all calculations +are expected to be exact. + + +.. [#] + .. versionadded:: 3.3 + +.. [#] + .. versionchanged:: 3.9 + This approach now works for all exact results except for non-integer powers. + Also backported to 3.7 and 3.8. From d6b730c5c5a13aed48922ea8edef888a2274f1d1 Mon Sep 17 00:00:00 2001 From: Stefan Krah Date: Fri, 21 Feb 2020 15:34:03 +0100 Subject: [PATCH 2/2] Appease the sphinx. --- Doc/library/decimal.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index 41d27de2d73422..2a51429bdff5c9 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -2130,7 +2130,7 @@ for very large numbers. The context must be adapted for exact arbitrary precision arithmetic. :attr:`Emin` and :attr:`Emax` should always be set to the maximum values, :attr:`clamp` -should always be `0` (the default). Setting :attr:`prec` requires some care. +should always be 0 (the default). Setting :attr:`prec` requires some care. The easiest approach for trying out bignum arithmetic is to use the maximum value for :attr:`prec` as well [#]_::