Compare commits

...

12 Commits

Author SHA1 Message Date
Landon Curt Noll
aeb9a9d473 Prepare for calc version 2.12.6.3 2017-09-06 18:20:35 -07:00
Landon Curt Noll
66883b390d Fixed CHANGES typo 2017-09-06 18:11:35 -07:00
Landon Curt Noll
ea533659ce Release calc version 2.12.6.2 2017-09-06 17:42:41 -07:00
Landon Curt Noll
9e81971f25 Verify that h*2^n-1 is not a multiple of 3 2017-09-06 17:41:56 -07:00
Landon Curt Noll
cbbd866535 Fixed a misleading indent reported by Thomas Walter 2017-09-06 17:40:49 -07:00
Landon Curt Noll
bf23f82c29 Correct comments relating to v(1) search table 2017-06-18 08:11:43 -07:00
Landon Curt Noll
ec5c584785 Fixed typo in lucas.cal comment 2017-06-18 04:11:44 -07:00
Landon Curt Noll
6bbb8c0e42 Update v(1) stats with full 1000000 test sample 2017-06-18 03:50:28 -07:00
Landon Curt Noll
438554b0ed Make a minor speedup to gen_v1(h,n) in lucas.cal 2017-06-14 16:50:58 -07:00
Landon Curt Noll
61ba4bc5c8 Improve lucas.cal v(1) search method & remarks 2017-06-14 16:30:42 -07:00
Landon Curt Noll
0145883396 Improved lucas.cal vt tables and arg checking 2017-06-09 15:44:48 -07:00
Landon Curt Noll
f91bfaab70 Prep for calc version 2.12.6.1 2017-06-05 21:05:25 -07:00
7 changed files with 273 additions and 141 deletions

15
CHANGES
View File

@@ -1,4 +1,16 @@
The following are the changes from calc version 2.12.6.0 to date:
The following are the changes from calc version 2.12.6.1 to date:
Improved gen_v1(h,n) in lucas.cal to use an even faster search method.
Improved are checking in lucas.cal. In particular both h and n must be
integers >= 1. In the case of both rodseth_xhn(x, h, n) and gen_v1(h, n)
h must be odd.
Fixed an C code indenting issue that was reported by Thomas Walter
<th dot walter42 at gmx dot de> in zfunc.c.
The following are the changes from calc version 2.12.6.0 to 2.12.6.0:
Added the makefile variable ${COMMON_ADD} that will add flags
to all compile and link commands. The ${COMMON_ADD} flags are
@@ -68,7 +80,6 @@ The following are the changes from calc version 2.12.6.0 to date:
Fixed a number of typos in the CHANGES file.
The following are the changes from calc version 2.12.5.4 to 2.12.5.6:
Recompile to match current RHEL7.2 libc and friends.

View File

@@ -990,7 +990,7 @@ EXT=
# The default calc versions
#
VERSION= 2.12.6.0
VERSION= 2.12.6.3
# Names of shared libraries with versions
#

View File

@@ -243,8 +243,8 @@ pprod256 = 0; /* product of "primes up to 256" / "primes up to 46" */
* do make this so.
*
* input:
* h the h as in h*2^n-1
* n the n as in h*2^n-1
* h h as in h*2^n-1 (must be >= 1)
* n n as in h*2^n-1 (must be >= 1)
*
* returns:
* 1 => h*2^n-1 is prime
@@ -267,13 +267,17 @@ lucas(h, n)
* check arg types
*/
if (!isint(h)) {
ldebug("lucas", "h is non-int");
quit "FATAL: bad args: h must be an integer";
}
if (h < 1) {
quit "FATAL: bad args: h must be an integer >= 1";
}
if (!isint(n)) {
ldebug("lucas", "n is non-int");
quit "FATAL: bad args: n must be an integer";
}
if (n < 1) {
quit "FATAL: bad args: n must be an integer >= 1";
}
/*
* reduce h if even
@@ -484,9 +488,9 @@ lucas(h, n)
* See the function gen_v1() for details on the value of v(1).
*
* input:
* h - h as in h*2^n-1
* n - n as in h*2^n-1
* v1 - gen_v1(h,n) (see function below)
* h - h as in h*2^n-1 (must be >= 1)
* n - n as in h*2^n-1 (must be >= 1)
* v1 - gen_v1(h,n) (must be >= 3) (see function below)
*
* returns:
* u(2) - initial value for Lucas test on h*2^n-1
@@ -499,6 +503,8 @@ gen_u2(h, n, v1)
local r; /* low value: v(n) */
local s; /* high value: v(n+1) */
local hbits; /* highest bit set in h */
local oldh; /* pre-reduced h */
local oldn; /* pre-reduced n */
local i;
/*
@@ -507,24 +513,45 @@ gen_u2(h, n, v1)
if (!isint(h)) {
quit "bad args: h must be an integer";
}
if (h < 0) {
quit "bad args: h must be an integer >= 1";
}
if (!isint(n)) {
quit "bad args: n must be an integer";
}
if (n < 1) {
quit "bad args: n must be an integer >= 1";
}
if (!isint(v1)) {
quit "bad args: v1 must be an integer";
}
if (v1 <= 0) {
quit "bogus arg: v1 is <= 0";
if (v1 < 3) {
quit "bogus arg: v1 must be an integer >= 3";
}
/*
* reduce h if even
*
* we will force h to be odd by moving powers of two over to 2^n
*/
oldh = h;
oldn = n;
shiftdown = fcnt(h,2); /* h % 2^shiftdown == 0, max shiftdown */
if (shiftdown > 0) {
h >>= shiftdown;
n += shiftdown;
}
/*
* enforce the h > 0 and n >= 2 rules
*/
if (h <= 0 || n < 1) {
print " ERROR: h=":oldh, "n=":oldn, "reduced h=":h, "n=":n;
quit "reduced args violate the rule: 0 < h < 2^n";
}
hbits = highbit(h);
if (hbits >= n) {
print " ERROR: h=":oldh, "n=":oldn, "reduced h=":h, "n=":n;
quit "reduced args violate the rule: 0 < h < 2^n";
}
@@ -599,8 +626,8 @@ gen_u2(h, n, v1)
* See the function gen_u2() for details.
*
* input:
* h - h as in h*2^n-1
* n - n as in h*2^n-1
* h - h as in h*2^n-1 (must be >= 1)
* n - n as in h*2^n-1 (must be >= 1)
* v1 - gen_v1(h,n) (see function below)
*
* returns:
@@ -638,9 +665,9 @@ gen_u0(h, n, v1)
* x > 2
*
* input:
* x - potential v(1) value
* h - h as in h*2^n-1
* n - n as in h*2^n-1
* x potential v(1) value
* h h as in h*2^n-1 (h must be odd >= 1)
* n n as in h*2^n-1 (must be >= 1)
*
* returns:
* 1 if v(1) == x for h*2^n-1
@@ -657,9 +684,18 @@ rodseth_xhn(x, h, n)
if (!isint(h)) {
quit "bad args: h must be an integer";
}
if (iseven(h)) {
quit "bad args: h must be an odd integer";
}
if (h < 1) {
quit "bad args: h must be an integer >= 1";
}
if (!isint(n)) {
quit "bad args: n must be an integer";
}
if (n < 1) {
quit "bad args: n must be an integer >= 1";
}
if (!isint(x)) {
quit "bad args: x must be an integer";
}
@@ -703,9 +739,9 @@ rodseth_xhn(x, h, n)
* We can show that X > 2. See the comments in the rodseth_xhn(x,h,n) above.
*
* Some values of X satisfy more often than others. For example a large sample
* of odd h, h multiple of 3 and large n (some around 1e4, some near 1e6, others
* near 3e7) where the sample size was 66 973 365, here is the count of the
* smallest value of X that satisfies conditions in Ref4, condition 1:
* of h*2^n-1, h odd multiple of 3, and large n (some around 1e4, some near 1e6,
* others near 3e7) where the sample size was 66 973 365, here is the count of
* the smallest value of X that satisfies conditions in Ref4, condition 1:
*
* count X
* ----------
@@ -763,45 +799,90 @@ rodseth_xhn(x, h, n)
* 1 161
* 1 155
*
* It is important that we select the smallest possible v(1). While testing
* various values of X for V(1) is fast, using larger than necessary values
* of V(1) of can slow down calculating V(h).
*
* The above distribution was found to hold fairly well over many values of
* odd h that are a multiple of 3 and for many values of n where h < 2^n.
* odd h that are also a multiple of 3 and for many values of n where h < 2^n.
* For example for in a sample size of 1000000 numbers of the form h*2^n-1
* where h is an odd multiple of 3, 12996351 <= h <= 13002351,
* 4331116 <= n <= 4332116, these are the smallest v(1) values that were found:
*
* smallest percentage
* v(1) used
* -------------------
* 3 40.0000%
* 5 25.6833%
* 9 11.6924%
* 11 10.4528%
* 15 4.8048%
* 17 2.3458%
* 21 1.6568%
* 29 1.2814%
* 27 0.6906%
* 35 0.4529%
* 39 0.3140%
* 41 0.1737%
* 31 0.1413%
* 45 0.1173%
* 51 0.0526%
* 55 0.0350%
* 49 0.0332%
* 59 0.0218%
* 69 0.0099%
* 65 0.0085%
* 71 0.0073%
* 57 0.0062%
* 85 0.0048%
* 81 0.0044%
* 95 0.0028%
* 99 0.0017%
* 77 0.0009%
* 53 0.0008%
* 67 0.0004%
* 105 0.0004%
* 111 0.0004%
* 125 0.0004%
* 87 0.0003%
* 101 0.0002%
* 83 0.0001%
* 109 0.0001%
* 121 0.0001%
* 129 0.0001%
*
* When h * 2^n-1 is prime and h is an odd multiple of 3, a smallest v(1) that
* is even is extremely rate. Of the list of 127287 known primes of the form
* h*2^n-1 when h was a multiple of 3, none has an smallest v(1) that was even.
*
* About 1 out of 1000000 cases when h is a multiple of 3 use v(1) > 127 as the
* smallest value of v(1).
*
* Given this information, when odd h is a multiple of 3 we try, in order,
* these values of X:
* these sorted values of X:
*
* 3, 5, 9, 11, 15, 17, 21, 29, 20, 27, 35, 36, 39, 41, 45, 32, 51, 44,
* 56, 49, 59, 57, 65, 55, 69, 71, 77, 81, 66, 95, 80, 67, 84, 99, 72,
* 74, 87, 90, 104, 101, 105, 109, 116, 111, 92
* 3, 5, 9, 11, 15, 17, 21, 27, 29, 31, 35, 39, 41, 45, 49, 51, 53, 55, 57, 59,
* 65, 67, 69, 71, 77, 81, 83, 85, 87, 95, 99, 101, 105, 109, 111, 121, 125
*
* And stop on the first value of X where:
*
* jacobi(X-2, h*2^n-1) == 1
* jacobi(X+2, h*2^n-1) == -1
*
* If no value in that list works, we start simple search starting with X = 120
* and incrementing by 1 until a value of X is found.
* If no value in that list works, we start simple search starting with X = 129
* and incrementing by 2 until a value of X is found.
*
* The x_tbl[] matrix contains those common values of X to try in order.
* If all x_tbl_len fail to satisfy Ref4 condition 1, then we begin a
* linear search at next_x until we find a proper X value.
*
* IMPORTANT NOTE: Using this table will not find the smallest possible v(1)
* for a given h and n. This is not a problem because using
* a larger value of v(1) does not impact the primality test.
* Furthermore after lucas(h, n) generates a few u(n) terms,
* the values will wrap (due to computing mod h*2^n-1).
* Finally on average, about 1/4 of the values of X work as
* v(1) for a given n when h is a multiple of 3. Skipping
* rarely used v(1) will not doom gen_v1() to a long search.
*/
x_tbl_len = 45;
x_tbl_len = 38;
mat x_tbl[x_tbl_len];
x_tbl = {
3, 5, 9, 11, 15, 17, 21, 29, 20, 27, 35, 36, 39, 41, 45, 32, 51, 44,
56, 49, 59, 57, 65, 55, 69, 71, 77, 81, 66, 95, 80, 67, 84, 99, 72,
74, 87, 90, 104, 101, 105, 109, 116, 111, 92
3, 5, 9, 11, 15, 17, 21, 27, 29, 31, 35, 39, 41, 45, 49, 51, 53, 55, 57, 59,
65, 67, 69, 71, 77, 81, 83, 85, 87, 95, 99, 101, 105, 109, 111, 121, 125
};
next_x = 120;
next_x = 129;
/*
* gen_v1 - compute the v(1) for a given h*2^n-1 if we can
@@ -956,11 +1037,12 @@ next_x = 120;
***
*
* input:
* h h as in h*2^n-1
* n n as in h*2^n-1
* h h as in h*2^n-1 (h must be odd >= 1)
* n n as in h*2^n-1 (must be >= 1)
*
* output:
* returns v(1), or -1 is there is no quick way
* returns v(1), or
* -1 when h*2^n-1 is a multiple of 3
*/
define
gen_v1(h, n)
@@ -974,9 +1056,26 @@ gen_v1(h, n)
if (!isint(h)) {
quit "bad args: h must be an integer";
}
if (iseven(h)) {
quit "bad args: h must be an odd integer";
}
if (h < 1) {
quit "bad args: h must be an integer >= 1";
}
if (!isint(n)) {
quit "bad args: n must be an integer";
}
if (n < 1) {
quit "bad args: n must be an integer >= 1";
}
/*
* pretest: Verify that h*2^n-1 is not a multiple of 3
*/
if (((h % 3 == 1) && (n % 2 == 0)) || ((h % 3 == 2) && (n % 2 == 1))) {
/* no need to test h*2^n-1, it is not prime */
return -1;
}
/*
* check for Case 1: (h mod 3 != 0)
@@ -995,6 +1094,11 @@ gen_v1(h, n)
*
* jacobi(X-2, h*2^n-1) == 1 part 1
* jacobi(X+2, h*2^n-1) == -1 part 2
*
* NOTE: If we wanted to be super optimial, we would cache
* jacobi(X+2, h*2^n-1) that that when we increment X
* to the next odd value, the now jacobi(X-2, h*2^n-1)
* does not need to be re-evaluted.
*/
for (i=0; i < x_tbl_len; ++i) {
@@ -1015,17 +1119,13 @@ gen_v1(h, n)
}
/*
* We are in that rare case (about 1 in 2 300 000) where none of the
* We are in that rare case (about 1 in 835 000) where none of the
* common X values satisfy Ref4 condition 1. We start a linear search
* at next_x from here on.
*
* However, we also need to keep in mind that when x+2 >= 257, we
* need to verify that gcd(x-2, h*2^n-1) == 1 and
* and to verify that gcd(x+2, h*2^n-1) == 1.
* of odd vules at next_x from here on.
*/
x = next_x;
while (rodseth_xhn(x, h, n) != 1) {
++x;
x += 2;
}
/* finally found a v(1) value */
ldebug("gen_v1", "h= " + str(h) + " n= " + str(n) +
@@ -1457,8 +1557,8 @@ legacy_d_qval[7] = 19; legacy_v1_qval[7] = 74; /* a=38 b=1 r=2 */
***
*
* input:
* h h as in h*2^n-1
* n n as in h*2^n-1
* h h as in h*2^n-1 (must be >= 1)
* n n as in h*2^n-1 (must be >= 1)
*
* output:
* returns v(1), or -1 is there is no quick way
@@ -1470,6 +1570,22 @@ legacy_gen_v1(h, n)
local val_mod; /* h*2^n-1 mod 'D' */
local i;
/*
* check arg types
*/
if (!isint(h)) {
quit "bad args: h must be an integer";
}
if (h < 1) {
quit "bad args: h must be an integer >= 1";
}
if (!isint(n)) {
quit "bad args: n must be an integer";
}
if (n < 1) {
quit "bad args: n must be an integer >= 1";
}
/*
* check for case 1
*/

View File

@@ -348,7 +348,7 @@ EXT=
# The default calc versions
#
VERSION= 2.12.6.0
VERSION= 2.12.6.3
# Names of shared libraries with versions
#

View File

@@ -348,7 +348,7 @@ EXT=
# The default calc versions
#
VERSION= 2.12.6.0
VERSION= 2.12.6.3
# Names of shared libraries with versions
#

View File

@@ -45,7 +45,7 @@ static char *program;
#define MAJOR_VER 2 /* major library version */
#define MINOR_VER 12 /* minor library version */
#define MAJOR_PATCH 6 /* major software level under library version */
#define MINOR_PATCH 0 /* minor software level or 0 if not patched */
#define MINOR_PATCH 3 /* minor software level or 0 if not patched */
/*

175
zfunc.c
View File

@@ -1029,93 +1029,98 @@ zgcd(ZVALUE z1, ZVALUE z2, ZVALUE *res)
needw = FALSE;
}
g = *a0 * w;
if (h < BASEB) g &= (1 << h) - 1;
else g &= BASE1;
if (h < BASEB) {
g &= (1 << h) - 1;
} else {
g &= BASE1;
}
} else {
g = 1;
}
else g = 1;
} else
} else {
g = (HALF) *a0 * w;
a = a0;
b = b0;
i = n;
if (g > 1) { /* a - g * b case */
f = 0;
while (i--) {
f = (FULL) *a - g * *b++ - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
if (f) {
i = m - n;
while (i-- && f) {
f = *a - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
}
while (m && !*a0) { /* Removing trailing zeros */
m--;
a0++;
}
if (f) { /* a - g * b < 0 */
while (m > 1 && a0[m-1] == BASE1) m--;
*a0 = - *a0;
a = a0;
i = m;
while (--i) {
a++;
*a = ~*a;
}
}
} else { /* abs(a - b) case */
while (i && *a++ == *b++) i--;
q = n - i;
if (m == n) { /* a and b same length */
if (i) { /* a not equal to b */
while (m && a0[m-1] == b0[m-1]) m--;
if (a0[m-1] < b0[m-1]) {
/* Swapping since a < b */
a = a0;
a0 = b0;
b0 = a;
k = j;
}
a = a0 + q;
b = b0 + q;
i = m - q;
f = 0;
while (i--) {
f = (FULL) *a - *b++ - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
}
} else { /* a has more digits than b */
a = a0 + q;
b = b0 + q;
i = n - q;
f = 0;
while (i--) {
f = (FULL) *a - *b++ - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
if (f) { while (!*a) *a++ = BASE1;
(*a)--;
}
}
a0 += q;
m -= q;
while (m && !*a0) { /* Removing trailing zeros */
m--;
a0++;
}
}
while (m && !a0[m-1]) m--; /* Removing leading zeros */
}
a = a0;
b = b0;
i = n;
if (g > 1) { /* a - g * b case */
f = 0;
while (i--) {
f = (FULL) *a - g * *b++ - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
if (f) {
i = m - n;
while (i-- && f) {
f = *a - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
}
while (m && !*a0) { /* Removing trailing zeros */
m--;
a0++;
}
if (f) { /* a - g * b < 0 */
while (m > 1 && a0[m-1] == BASE1) m--;
*a0 = - *a0;
a = a0;
i = m;
while (--i) {
a++;
*a = ~*a;
}
}
} else { /* abs(a - b) case */
while (i && *a++ == *b++) i--;
q = n - i;
if (m == n) { /* a and b same length */
if (i) { /* a not equal to b */
while (m && a0[m-1] == b0[m-1]) m--;
if (a0[m-1] < b0[m-1]) {
/* Swapping since a < b */
a = a0;
a0 = b0;
b0 = a;
k = j;
}
a = a0 + q;
b = b0 + q;
i = m - q;
f = 0;
while (i--) {
f = (FULL) *a - *b++ - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
}
} else { /* a has more digits than b */
a = a0 + q;
b = b0 + q;
i = n - q;
f = 0;
while (i--) {
f = (FULL) *a - *b++ - f;
*a++ = (HALF) f;
f >>= BASEB;
f = -f & BASE1;
}
if (f) { while (!*a) *a++ = BASE1;
(*a)--;
}
}
a0 += q;
m -= q;
while (m && !*a0) { /* Removing trailing zeros */
m--;
a0++;
}
}
while (m && !a0[m-1]) m--; /* Removing leading zeros */
}
if (m == 1) { /* a has one digit */
v = *a0;