chiark / gitweb /
Merge remote-tracking branch 'origin/HEAD'
[catacomb-python] / mp.c
diff --git a/mp.c b/mp.c
index 8f57ad12ec251dc8e56b848077d354687bfe6e6f..88ee73813b538baa863097df8f07232a4fe66523 100644 (file)
--- a/mp.c
+++ b/mp.c
@@ -163,7 +163,7 @@ PyObject *gf_pywrap(mp *x)
   return ((PyObject *)z);
 }
 
-int mp_tolong_checked(mp *x, long *l)
+int mp_tolong_checked(mp *x, long *l, int must)
 {
   static mp *longmin = 0, *longmax = 0;
   int rc = -1;
@@ -172,8 +172,10 @@ int mp_tolong_checked(mp *x, long *l)
     longmin = mp_fromlong(MP_NEW, LONG_MIN);
     longmax = mp_fromlong(MP_NEW, LONG_MAX);
   }
-  if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax))
-    VALERR("mp out of range for int");
+  if (MP_CMP(x, <, longmin) || MP_CMP(x, >, longmax)) {
+    if (must) VALERR("mp out of range for int");
+    else goto end;
+  }
   *l = mp_tolong(x);
   rc = 0;
 end:
@@ -362,7 +364,7 @@ static PyObject *mp_pyid(PyObject *x) { RETURN_OBJ(x); }
     PyObject *z = 0;                                                   \
     long n;                                                            \
     if (pre##binop(x, y, &xx, &yy)) RETURN_NOTIMPL;                    \
-    if (mp_tolong_checked(yy, &n)) goto end;                           \
+    if (mp_tolong_checked(yy, &n, 1)) goto end;                                \
     if (n < 0)                                                         \
       z = pre##_pywrap(mp_##rname(MP_NEW, xx, -n));                    \
     else                                                               \
@@ -483,8 +485,8 @@ static int mp_pynonzerop(PyObject *x) { return !MP_ZEROP(MP_X(x)); }
 static PyObject *mp_pyint(PyObject *x)
 {
   long l;
-  if (mp_tolong_checked(MP_X(x), &l)) return (0);
-  return (PyInt_FromLong(l));
+  if (!mp_tolong_checked(MP_X(x), &l, 0)) return (PyInt_FromLong(l));
+  else return mp_topylong(MP_X(x));
 }
 static PyObject *mp_pylong(PyObject *x)
   { return (mp_topylong(MP_X(x))); }
@@ -680,6 +682,19 @@ end:
   return (z);
 }
 
+static PyObject *mpmeth_leastcongruent(PyObject *me, PyObject *arg)
+{
+  mp *z, *b, *m;
+  PyObject *rc = 0;
+
+  if (!PyArg_ParseTuple(arg, "O&O&:leastcongruent", convmp, &b, convmp, &m))
+    goto end;
+  z = mp_leastcongruent(MP_NEW, b, MP_X(me), m);
+  rc = mp_pywrap(z);
+end:
+  return (rc);
+}
+
 #define STOREOP(name, c)                                               \
   static PyObject *mpmeth_##name(PyObject *me,                         \
                                 PyObject *arg, PyObject *kw)           \
@@ -711,7 +726,7 @@ STOREOP(storeb2c, 2c)
   {                                                                    \
     buf b;                                                             \
     char *p;                                                           \
-    int sz;                                                            \
+    Py_ssize_t sz;                                                     \
     PyObject *rc = 0;                                                  \
     mp *x;                                                             \
                                                                        \
@@ -790,6 +805,8 @@ static PyMethodDef mp_pymethods[] = {
         "X.gcdx(Y) -> (gcd(X, Y), U, V) with X U + Y V = gcd(X, Y)")
   METH (modinv,        "X.modinv(Y) -> multiplicative inverse of Y mod X")
   METH (modsqrt,       "X.modsqrt(Y) -> square root of Y mod X, if X prime")
+  METH (leastcongruent,
+        "X.leastcongruent(B, M) -> smallest Z >= B with Z == X (mod M)")
   KWMETH(primep,       "X.primep(rng = rand) -> true/false if X is prime")
   KWMETH(tostring,     "X.tostring(radix = 10) -> STR")
   KWMETH(storel,       "X.storel(len = -1) -> little-endian bytes")
@@ -909,7 +926,7 @@ static PyObject *meth__MP_fromstring(PyObject *me,
 {
   int r = 0;
   char *p;
-  int len;
+  Py_ssize_t len;
   PyObject *z = 0;
   mp *zz;
   mptext_stringctx sc;
@@ -922,7 +939,8 @@ static PyObject *meth__MP_fromstring(PyObject *me,
   sc.buf = p; sc.lim = p + len;
   if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0)
     VALERR("bad integer");
-  z = Py_BuildValue("(Ns#)", mp_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
+  z = Py_BuildValue("(Ns#)", mp_pywrap(zz),
+                   sc.buf, (Py_ssize_t)(sc.lim - sc.buf));
 end:
   return (z);
 }
@@ -950,7 +968,7 @@ static PyObject *meth__MP_fibonacci(PyObject *me, PyObject *arg)
   static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg)    \
   {                                                                    \
     char *p;                                                           \
-    int len;                                                           \
+    Py_ssize_t len;                                                    \
     if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \
     return (pre##_pywrap(mp_##name(MP_NEW, p, len)));                  \
   }
@@ -2109,7 +2127,7 @@ static PyObject *meth__GF_fromstring(PyObject *me,
 {
   int r = 0;
   char *p;
-  int len;
+  Py_ssize_t len;
   PyObject *z = 0;
   mp *zz;
   mptext_stringctx sc;
@@ -2125,7 +2143,8 @@ static PyObject *meth__GF_fromstring(PyObject *me,
     if (zz) MP_DROP(zz);
     VALERR("bad binary polynomial");
   }
-  z = Py_BuildValue("(Ns#)", gf_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf));
+  z = Py_BuildValue("(Ns#)", gf_pywrap(zz),
+                   sc.buf, (Py_ssize_t)(sc.lim - sc.buf));
 end:
   return (z);
 }