]> granicus.if.org Git - python/commitdiff
Issue #19171: speed some cases of 3-argument long pow().
authorTim Peters <tim@python.org>
Sat, 5 Oct 2013 21:53:52 +0000 (16:53 -0500)
committerTim Peters <tim@python.org>
Sat, 5 Oct 2013 21:53:52 +0000 (16:53 -0500)
Reduce the base by the modulus when the base is larger than
the modulus.  This can unboundedly speed the "startup costs"
of doing modular exponentiation, particularly in cases where
the base is much larger than the modulus.  Original patch
by Armin Rigo, inspired by https://github.com/pyca/ed25519.
(grafted from f34c59494420765b013136ca93f63b716d9f1d30)

Objects/longobject.c

index fb740dc4d6c87ad6eead1415e8e10bac76424789..405be2e045a62a713c826811ee2288676848d32d 100644 (file)
@@ -3474,10 +3474,16 @@ long_pow(PyObject *v, PyObject *w, PyObject *x)
             goto Done;
         }
 
-        /* if base < 0:
-               base = base % modulus
-           Having the base positive just makes things easier. */
-        if (Py_SIZE(a) < 0) {
+        /* Reduce base by modulus in some cases:
+           1. If base < 0.  Forcing the base non-negative makes things easier.
+           2. If base is obviously larger than the modulus.  The "small
+              exponent" case later can multiply directly by base repeatedly,
+              while the "large exponent" case multiplies directly by base 31
+              times.  It can be unboundedly faster to multiply by
+              base % modulus instead.
+           We could _always_ do this reduction, but l_divmod() isn't cheap,
+           so we only do it when it buys something. */
+        if (Py_SIZE(a) < 0 || Py_SIZE(a) > Py_SIZE(c)) {
             if (l_divmod(a, c, NULL, &temp) < 0)
                 goto Error;
             Py_DECREF(a);