[gnumeric] Numtheory: speed things up.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnumeric] Numtheory: speed things up.
- Date: Mon, 27 Nov 2017 15:36:10 +0000 (UTC)
commit d4c8c5cfaf395b48695f0cec12d11cccde036ce2
Author: Morten Welinder <terra gnome org>
Date: Mon Nov 27 10:35:43 2017 -0500
Numtheory: speed things up.
NEWS | 1 +
plugins/fn-numtheory/ChangeLog | 3 +-
plugins/fn-numtheory/numtheory.c | 65 ++++++++++++++++++-------------------
3 files changed, 34 insertions(+), 35 deletions(-)
---
diff --git a/NEWS b/NEWS
index 3f09403..5dba03b 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ Morten:
* Improve xlsx export of cell comments. [#790756]
* Plug leaks.
* Fix potential crash on exit.
+ * Speed-up number theory functions.
--------------------------------------------------------------------------
Gnumeric 1.12.36
diff --git a/plugins/fn-numtheory/ChangeLog b/plugins/fn-numtheory/ChangeLog
index 0f558d8..50c933c 100644
--- a/plugins/fn-numtheory/ChangeLog
+++ b/plugins/fn-numtheory/ChangeLog
@@ -1,7 +1,6 @@
2017-11-27 Morten Welinder <terra gnome org>
- * numtheory.c (ithprime): For each new candidate we at most need
- to consider one extra prime divisor.
+ * numtheory.c (ithprime): switch to explicit sieve. Much faster.
2017-11-23 Morten Welinder <terra gnome org>
diff --git a/plugins/fn-numtheory/numtheory.c b/plugins/fn-numtheory/numtheory.c
index 2d8258b..b5dbd2a 100644
--- a/plugins/fn-numtheory/numtheory.c
+++ b/plugins/fn-numtheory/numtheory.c
@@ -64,57 +64,56 @@ intpow (int p, int v)
#define ITHPRIME_LIMIT 10000000
static guint *prime_table = NULL;
-/* Calculate the i-th prime. Returns TRUE on error. */
+// Bit-field macros for sieve. Note that only odd indices are used.
+#define SIEVE_ITEM(u_) s[(u_) >> 4]
+#define SIEVE_BIT(u_) (1u << (((u_) >> 1) & 7))
+
+/* Calculate the i-th prime. Returns TRUE on too-big-to-handle error. */
static gboolean
ithprime (int i, guint64 *res)
{
- static guint computed = 0;
- static guint allocated = 0;
-
if (i < 1 || (guint)i > ITHPRIME_LIMIT)
return TRUE;
- if ((guint)i > computed) {
- static guint candidate, jlim;
-
- if ((guint)i > allocated) {
- allocated = MAX ((guint)i, 2 * allocated + 100);
- allocated = MIN (allocated, ITHPRIME_LIMIT);
- prime_table = g_renew (guint, prime_table, allocated);
- if (computed == 0) {
- prime_table[computed++] = 2;
- candidate = prime_table[computed++] = 3;
- jlim = 1;
- g_assert (candidate < prime_table[jlim] * prime_table[jlim]);
- }
- }
+ if (!prime_table) {
+ // Compute an upper bound of the largest prime we need.
+ // See https://en.wikipedia.org/wiki/Prime_number_theorem
+ guint ub = (guint)
+ (ITHPRIME_LIMIT *
+ (log (ITHPRIME_LIMIT) + log (log (ITHPRIME_LIMIT))));
+ guint8 *s = g_new0 (guint8, (ub >> 4) + 1);
+ guint N = 0, c;
+ guint L = (int)sqrt (ub);
- while ((guint)i > computed) {
- gboolean prime = TRUE;
- guint j;
+ prime_table = g_new (guint, ITHPRIME_LIMIT);
+ prime_table[N++] = 2;
- candidate += 2; /* Skip even candidates. */
+ for (c = 3; N < ITHPRIME_LIMIT; c += 2) {
+ guint d;
- // We at most need to consider one extra candidate
- if (candidate >= prime_table[jlim] * prime_table[jlim])
- jlim++;
+ if (SIEVE_ITEM (c) & SIEVE_BIT (c))
+ continue;
- for (j = 1; j < jlim; j++) {
- if (candidate % prime_table[j] == 0) {
- prime = FALSE;
- break;
- }
- }
+ prime_table[N++] = c;
+ if (c > L)
+ continue; // Prevents square overflow
- if (prime)
- prime_table[computed++] = candidate;
+ // Tag all odd multiples starting with c^2
+ for (d = c * c; d <= ub; d += 2 * c)
+ SIEVE_ITEM (d) |= SIEVE_BIT (d);
}
+
+ g_free (s);
}
*res = prime_table[i - 1];
return FALSE;
}
+#undef SIEVE_ITEM
+#undef SIEVE_BIT
+
+
/*
* A function useful for computing multiplicative arithmetic functions.
* Returns TRUE on error.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]