Il 2020-03-24 01:10 Seth Troisi ha scritto:
(I'm don't think your ulong patch is needed but I can measure at a

It's a small patch, but the speed-up it gives is probably too small to be worth adding.

My code doesn't use a sieve (and instead checks each number for
divisors similar to the old code) because the average gap for small
numbers is small 300000 / primepi(300000) = 11

There is a small error in the code, it does not handle negative numbers correctly.

For each divisor your code uses two operations, a product (prime*prime) and a remainder (t % prime). On many architectures computing t/prime and t%prime cost just one operation... that's why I'd use the ideas Torbjorn used in isprime() in dumbmp.c, https://gmplib.org/repo/gmp/rev/7524222ab7d4 currently in bootstrap.c .

I propose a variation of your patch, you find it attached, on my computer it's faster.

Because the measured threshold for this was much larger (~80 million),
it might actually make sense to use a sieve after some threshold

If you think that's a 1.5-3x speedup for inputs 16-30bits is important
I can try to dynamically generate a longer list of primes

If writing the code is not too complex, it may be interesting to test if it is worth.

On Mon, Mar 23, 2020 at 2:38 PM Marco Bodrato
<bodr...@mail.dm.unipi.it> wrote:

It might also be useful to commit tune_nextprime_small which
dynamically selects a higher reps count for
mpz_nextprime input and helps increase precision.

Uhm...
j = 200000 / s->size;

This is a great point, I modified the code so It only changes the
outer loop count.
I included a screenshot showing how much this reduces variance over
multiple runs.

Did you try tweaking with the -p parameter? It can be useful when a measure is "noisy".

PS: a comment in the current code says
/* Larger threshold is faster but takes ~O(n/ln(n)) memory.
To be honest, the array sieve needs n/24 bytes, and the array

You are correct, let's change the comment by which I mean you :)

Done.

Ĝis,
m

--
http://bodrato.it/papers/
diff -r a7836288d2c0 mpz/nextprime.c
--- a/mpz/nextprime.c	Fri Mar 20 16:19:07 2020 +0100
+++ b/mpz/nextprime.c	Tue Mar 24 17:24:41 2020 +0100
@@ -85,6 +85,9 @@
 };
 
 #define NUMBER_OF_PRIMES 100
+#define LAST_PRIME 557
+/* NP_SMALL_LIMIT = prevprime (LAST_PRIME ^ 2) */
+#define NP_SMALL_LIMIT 310243
 
 static unsigned long
 calculate_sievelimit(mp_bitcnt_t nbits) {
@@ -120,6 +123,32 @@
   return sieve_limit;
 }
 
+static unsigned
+mpz_nextprime_small (unsigned t)
+{
+  ASSERT (t > 0); /* Expect t=1 if the operand was smaller.*/
+  /* Technically this should be prev_prime(LAST_PRIME ^ 2) */
+  ASSERT (t < NP_SMALL_LIMIT);
+
+  /* Start from next candidate (2 or odd) */
+  t = (t + 1) | (t > 1);
+  for (; ; t += 2)
+    {
+      unsigned prime = 3;
+      for (int i = 0; ; prime += primegap_small[i++])
+	{
+	  unsigned q, r;
+	  q = t / prime;
+	  r = t - q * prime; /* r = t % prime; */
+	  if (q < prime)
+	    return t;
+	  if (r == 0)
+	    break;
+	  ASSERT (i < NUMBER_OF_PRIMES);
+	}
+    }
+}
+
 void
 mpz_nextprime (mpz_ptr p, mpz_srcptr n)
 {
@@ -132,18 +161,16 @@
   unsigned odds_in_composite_sieve;
   TMP_DECL;
 
-  /* First handle tiny numbers */
-  if (mpz_cmp_ui (n, 2) < 0)
+  /* First handle small numbers */
+  if (mpz_cmp_ui (n, NP_SMALL_LIMIT) < 0)
     {
-      mpz_set_ui (p, 2);
+      ASSERT (NP_SMALL_LIMIT < UINT_MAX);
+      mpz_set_ui (p, mpz_nextprime_small (SIZ (n) > 0 ? mpz_get_ui (n) : 1));
       return;
     }
   mpz_add_ui (p, n, 1);
   mpz_setbit (p, 0);
 
-  if (mpz_cmp_ui (p, 7) <= 0)
-    return;
-
   TMP_MARK;
   pn = SIZ(p);
   MPN_SIZEINBASE_2EXP(nbits, PTR(p), pn, 1);
_______________________________________________
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel

Reply via email to