# [Python-Dev] SIGCHECK() in longobject.c

Mark Dickinson dickinsm at gmail.com
Tue Oct 20 10:39:31 CEST 2009

```On Mon, Oct 19, 2009 at 9:58 PM, Tim Peters <tim.peters at gmail.com> wrote:
> Don't want to hijack this thread, but this is the kind of use case
> justifying keeping the 3-argument pow in the decimal module.  People
> "playing" with number theory questions can learn a bag of tricks to
> worm around that non-decimal arithmetic can make it inconvenient &
> slow to get answers about decimal digits, but most people -- and
> especially beginners -- find life easier when doing calculations in
> decimal to begin with.  Then they can use obvious methods, and not get
> sidetracked by wondering why they take forever to finish.

That's true.  I wouldn't relish the task of trying to teach the decimal
module at the same time as introducing students to Python and to
elementary number theory, though. It's not the most friendly module
to get started with.

> Although, to be fair, I started
>
>>>> decimal.getcontext().prec = 20000000
>>>> p10 = pow(decimal.Decimal(2), 43112609)
>
> before I started typing this, and am still waiting for it to finish ;-)

Hmm, yes.  The decimal module isn't (currently) well set up
for this sort of calculation, mostly because almost every operation
is implemented by converting to binary, invoking the appropriate
int/long arithmetic operation, and converting back.  Since the
conversion is O(n^2), even addition and multiplication of Decimal
instances end up being O(n^2) operations at the moment, instead
of getting the linear and Karatsuba (resp.) running times that they
deserve.

(The exception is rounding operations, which don't do any
decimal <-> binary operations, but operate directly on the
coefficient in its representation as a string of decimal digits.)

This high-precision inefficiency could easily be fixed by
using a dedicated 'decimal natural number' extension
type for the Decimal coefficient, stored internally in base
a suitable power of 10.  I think this may be worth
considering seriously. I'm not proposing this as an alternative
to the huge task of rewriting the entire decimal module in C,
by the way;  it would be more a stop-gap measure that would
be easy to implement, would slightly increase efficiency for
normal operations, and vastly increase efficiency for high-precision
operations.

>
> OTOH,
>
>>>> decimal.getcontext().prec = 200
>>>> pow(decimal.Decimal(2), 43112609)   # get the first 100 digits (& then some)
>
> and
>
>>>> pow(decimal.Decimal(2), 43112609, 10**100) - 1  # get the last 100 digits
>
> both appear to work instantaneously.
>

Right.  Low precision Decimal operations should be fine.  I don't
really see the advantage of the second operation over a simple

pow(2, 43112609, 10**100)

though.

By the way, despite the above use-case, and despite the fact
that I use it frequently, I still don't believe 3-argument pow belongs
in the core.  But that's probably a discussion topic for Python 4000.

Mark
```