[Gmp-commit] /var/hg/gmp-proj/mini-gmp: 2 new changesets
mercurial at gmplib.org
mercurial at gmplib.org
Wed Jan 4 23:42:14 CET 2012
details: /var/hg/gmp-proj/mini-gmp/rev/ee0425fe3e0f
changeset: 46:ee0425fe3e0f
user: Niels M?ller <nisse at lysator.liu.se>
date: Wed Jan 04 21:56:54 2012 +0100
description:
Strike mpz_powm from TODO list.
details: /var/hg/gmp-proj/mini-gmp/rev/d74bc57c9fa5
changeset: 47:d74bc57c9fa5
user: Niels M?ller <nisse at lysator.liu.se>
date: Wed Jan 04 23:42:06 2012 +0100
description:
Implemented mpz_sqrtrem.
diffstat:
.hgignore | 1 +
mini-gmp.c | 59 +++++++++++++++++++++++++++++++++++++++++++--
mini-gmp.h | 2 +
tests/Makefile | 2 +-
tests/t-sqrt.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 135 insertions(+), 4 deletions(-)
diffs (190 lines):
diff -r b753004ece2c -r d74bc57c9fa5 .hgignore
--- a/.hgignore Wed Jan 04 21:25:37 2012 +0100
+++ b/.hgignore Wed Jan 04 23:42:06 2012 +0100
@@ -10,6 +10,7 @@
^tests/t-div$
^tests/t-double$
^tests/t-gcd$
+^tests/t-sqrt
^tests/t-powm$
^tests/t-logops$
^tests/t-str$
diff -r b753004ece2c -r d74bc57c9fa5 mini-gmp.c
--- a/mini-gmp.c Wed Jan 04 21:25:37 2012 +0100
+++ b/mini-gmp.c Wed Jan 04 23:42:06 2012 +0100
@@ -36,9 +36,6 @@
mpz_hamdist
mpz_lcm_ui
mpz_popcount
- mpz_powm
- mpz_sqrtrem
- mpz_tstbit
*/
#include <assert.h>
#include <ctype.h>
@@ -2347,6 +2344,62 @@
return invertible;
}
+/* Compute s = floor(sqrt(u)) and r = u - s^2 */
+void
+mpz_sqrtrem (mpz_t s, mpz_t r, const mpz_t u)
+{
+ mpz_t x, t, dx, q;
+
+ if (u->_mp_size < 0)
+ gmp_die ("mpz_sqrtrem: Negative argument.");
+ if (u->_mp_size == 0)
+ {
+ mpz_set_ui (s, 0);
+ mpz_set_ui (r, 0);
+ return;
+ }
+
+ mpz_init (x);
+ mpz_init (t);
+ mpz_init (dx);
+ mpz_init (q);
+
+ /* Make x > sqrt(a). This will be invariant through the loop. */
+ mpz_setbit (x, (mpz_sizeinbase (u, 2) + 1) / 2);
+
+ for (;;)
+ {
+ /* Compute x^2 - u */
+ mpz_mul (t, x, x);
+ mpz_sub (t, t, u);
+ assert (t->_mp_size > 0);
+
+ mpz_mul_2exp (dx, x, 1);
+ mpz_tdiv_q (q, t, dx);
+ if (q->_mp_size == 0)
+ break;
+ mpz_sub (x, x, q);
+ assert (x->_mp_size > 0);
+ }
+ /* We have 0 < u - x^2 < 2x, which implies that sqrt(a) < x < 1 +
+ sqrt(1+a), and x-1 = floor(sqrt(a)). Then r = a - (x-1)^2 = 2x -
+ 1 - t. */
+ mpz_sub_ui (x, x, 1);
+ assert (x->_mp_size > 0);
+
+ mpz_sub_ui (dx, dx, 1);
+ mpz_sub (t, dx, t);
+ assert (t->_mp_size >= 0);
+
+ mpz_swap (s, x);
+ mpz_swap (t, r);
+
+ mpz_clear (x);
+ mpz_clear (t);
+ mpz_clear (dx);
+ mpz_clear (q);
+}
+
void
mpz_powm (mpz_t r, const mpz_t b, const mpz_t e, const mpz_t m)
{
diff -r b753004ece2c -r d74bc57c9fa5 mini-gmp.h
--- a/mini-gmp.h Wed Jan 04 21:25:37 2012 +0100
+++ b/mini-gmp.h Wed Jan 04 23:42:06 2012 +0100
@@ -136,6 +136,8 @@
void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
int mpz_invert (mpz_t, const mpz_t, const mpz_t);
+void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
+
void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
int mpz_tstbit (const mpz_t, mp_bitcnt_t);
diff -r b753004ece2c -r d74bc57c9fa5 tests/Makefile
--- a/tests/Makefile Wed Jan 04 21:25:37 2012 +0100
+++ b/tests/Makefile Wed Jan 04 23:42:06 2012 +0100
@@ -7,7 +7,7 @@
LIBS = -lgmp -lm -lmcheck
CHECK_PROGRAMS = t-add t-sub t-mul t-invert t-div t-double t-gcd \
- t-powm t-logops t-str
+ t-sqrt t-powm t-logops t-str
MISC_OBJS = hex-random.o mini-random.o mini-gmp.o
diff -r b753004ece2c -r d74bc57c9fa5 tests/t-sqrt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/t-sqrt.c Wed Jan 04 23:42:06 2012 +0100
@@ -0,0 +1,75 @@
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "mini-random.h"
+
+#define MAXBITS 400
+#define COUNT 10000
+
+static void
+dump (const char *label, const mpz_t x)
+{
+ char *buf = mpz_get_str (NULL, 16, x);
+ fprintf (stderr, "%s: %s\n", label, buf);
+ free (buf);
+}
+
+/* Called when s is supposed to be floor(sqrt(u)), and r = u - s^2 */
+static int
+sqrtrem_valid_p (const mpz_t u, const mpz_t s, const mpz_t r)
+{
+ mpz_t t;
+
+ mpz_init (t);
+ mpz_mul (t, s, s);
+ mpz_sub (t, u, t);
+ if (mpz_sgn (t) < 0 || mpz_cmp (t, r) != 0)
+ {
+ mpz_clear (t);
+ return 0;
+ }
+ mpz_add_ui (t, s, 1);
+ mpz_mul (t, t, t);
+ if (mpz_cmp (t, u) <= 0)
+ {
+ mpz_clear (t);
+ return 0;
+ }
+
+ mpz_clear (t);
+ return 1;
+}
+
+int
+main (int argc, char **argv)
+{
+ unsigned i;
+ mpz_t u, s, r;
+
+ hex_random_init ();
+
+ mpz_init (u);
+ mpz_init (s);
+ mpz_init (r);
+
+ for (i = 0; i < COUNT; i++)
+ {
+ mini_rrandomb (u, MAXBITS);
+ mpz_sqrtrem (s, r, u);
+
+ if (!sqrtrem_valid_p (u, s, r))
+ {
+ fprintf (stderr, "mpz_sqrtrem failed:\n");
+ dump ("u", u);
+ dump ("sqrt", s);
+ dump ("rem", r);
+ abort ();
+ }
+ }
+ mpz_clear (u);
+ mpz_clear (s);
+ mpz_clear (r);
+
+ return 0;
+}
More information about the gmp-commit
mailing list