mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Release calc version 2.10.3t5.45
This commit is contained in:
309
lib/mfactor.cal
309
lib/mfactor.cal
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996 Landon Curt Noll
|
||||
* Copyright (c) 1997 Landon Curt Noll
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and
|
||||
* its documentation for any purpose and without fee is hereby granted,
|
||||
@@ -23,6 +23,95 @@
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* hset method
|
||||
*
|
||||
* We will assume that mfactor is called with p_elim == 17.
|
||||
*
|
||||
* n = (the Mersenne exponent we are testing)
|
||||
* Q = 4*2*3*5*7*11*13*17 (4 * pfact(of some reasonable integer))
|
||||
*
|
||||
* We first determine all values of h mod Q such that:
|
||||
*
|
||||
* gcd(h*n+1, Q) == 1 and h*n+1 == +/-1 mod 8
|
||||
*
|
||||
* There will be 2*1*2*4*6*10*12*16 such values of h.
|
||||
*
|
||||
* For efficiency, we keep the difference between consecutive h values
|
||||
* in the hset[] difference array with hset[0] being the first h value.
|
||||
* Last, we multiply the hset[] values by n so that we only need
|
||||
* to add sequential values of hset[] to get factor candidates.
|
||||
*
|
||||
* We need only test factors of the form:
|
||||
*
|
||||
* (Q*g*n + hx) + 1
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* g is an integer >= 0
|
||||
* hx is computed from hset[] difference value described above
|
||||
*
|
||||
* Note that (Q*g*n + hx) is always even and that hx is a multiple
|
||||
* of n. Thus the typical factor form:
|
||||
*
|
||||
* 2*k*n + 1
|
||||
*
|
||||
* implies that:
|
||||
*
|
||||
* k = (Q*g + hx/n)/2
|
||||
*
|
||||
* This allows us to quickly eliminate factor values that are divisible
|
||||
* by 2, 3, 5, 7, 11, 13 or 17. (well <= p value found below)
|
||||
*
|
||||
* The following loop shows how test_factor is advanced to higher test
|
||||
* values using hset[]. Here, hcount is the number of elements in hset[].
|
||||
* It can be shown that hset[0] == 0. We add hset[hcount] to the hset[]
|
||||
* array for looping control convenience.
|
||||
*
|
||||
* (* increase test_factor thru other possible test values *)
|
||||
* test_factor = 0;
|
||||
* hindx = 0;
|
||||
* do {
|
||||
* while (++hindx <= hcount) {
|
||||
* test_factor += hset[hindx];
|
||||
* }
|
||||
* hindx = 0;
|
||||
* } while (test_factor < some_limit);
|
||||
*
|
||||
* The test, mfactor(67, 1, 10000) took on an 200 Mhz r4k (user CPU seconds):
|
||||
*
|
||||
* 210.83 (prior to use of hset[])
|
||||
* 78.35 (hset[] for p_elim = 7)
|
||||
* 73.87 (hset[] for p_elim = 11)
|
||||
* 73.92 (hset[] for p_elim = 13)
|
||||
* 234.16 (hset[] for p_elim = 17)
|
||||
* p_elim == 19 requires over 190 Megs of memory
|
||||
*
|
||||
* Over a long period of time, the call to load_hset() becomes insignificant.
|
||||
* If we look at the user CPU seconds from the first 10000 cycle to the
|
||||
* end of the test we find:
|
||||
*
|
||||
* 205.00 (prior to use of hset[])
|
||||
* 75.89 (hset[] for p_elim = 7)
|
||||
* 73.74 (hset[] for p_elim = 11)
|
||||
* 70.61 (hset[] for p_elim = 13)
|
||||
* 57.78 (hset[] for p_elim = 17)
|
||||
* p_elim == 19 rejected because of memory size
|
||||
*
|
||||
* The p_elim == 17 overhead takes ~3 minutes on an 200 Mhz r4k CPU and
|
||||
* requires about ~13 Megs of memory. The p_elim == 13 overhead
|
||||
* takes about 3 seconds and requires ~1.5 Megs of memory.
|
||||
*
|
||||
* The value p_elim == 17 is best for long factorizations. It is the
|
||||
* fastest even thought the initial startup overhead is larger than
|
||||
* for p_elim == 13.
|
||||
*
|
||||
* NOTE: The values above are prior to optimizations where hset[] was
|
||||
* multiplied by n plus other optimizations. Thus, the CPU
|
||||
* times you may get will not likely match the above values.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* mfactor - find a factor of a Mersenne Number
|
||||
*
|
||||
@@ -34,22 +123,33 @@
|
||||
*
|
||||
* 2*k*n+1 and +/- 1 mod 8
|
||||
*
|
||||
* We make use of the hset[] difference array to eliminate factor
|
||||
* candidates that would otherwise be divisible by 2, 3, 5, 7 ... p_elim.
|
||||
*
|
||||
* given:
|
||||
* n attempt to factor M(n) = 2^n-1
|
||||
* start_k the value k in 2*k*n+1 to start the search
|
||||
* rept_loop loop cycle reporting, 0 => none
|
||||
* start_k the value k in 2*k*n+1 to start the search (def: 1)
|
||||
* rept_loop loop cycle reporting (def: 10000)
|
||||
* p_elim largest prime to eliminate from test factors (def: 17)
|
||||
*
|
||||
* returns:
|
||||
* factor of M(n)
|
||||
* factor of (2^n)-1
|
||||
*
|
||||
* NOTE: The p_elim argument is optional and defaults to 17. A p_elim value
|
||||
* of 17 is faster than 13 for even medium length runs. However 13
|
||||
* uses less memory and has a shorter startup time.
|
||||
*/
|
||||
define mfactor(n, start_k, rept_loop)
|
||||
define mfactor(n, start_k, rept_loop, p_elim)
|
||||
{
|
||||
local q; /* test factor 2*k*n+1 */
|
||||
local k; /* k in 2*k*n+1 */
|
||||
local step2; /* 2*n */
|
||||
local step6; /* 6*n */
|
||||
local mod8; /* q mod 8 */
|
||||
local Q; /* 4*pfact(p_elim), hset[] cycle size */
|
||||
local hcount; /* elements in the hset[] difference array */
|
||||
local loop; /* report loop count */
|
||||
local q; /* test factor of 2^n-1 */
|
||||
local g; /* g as in test candidate form: (Q*g*hset[i])*n + 1 */
|
||||
local hindx; /* hset[] index */
|
||||
local i;
|
||||
local tmp;
|
||||
local tmp2;
|
||||
|
||||
/*
|
||||
* firewall
|
||||
@@ -57,101 +157,158 @@ define mfactor(n, start_k, rept_loop)
|
||||
if (!isint(n) || n <= 0) {
|
||||
quit "n must be an integer > 0";
|
||||
}
|
||||
if (isnull(start_k)) {
|
||||
if (!isint(start_k)) {
|
||||
start_k = 1;
|
||||
} else if (!isint(start_k) || start_k <= 0) {
|
||||
quit "start_k must be an integer > 0";
|
||||
}
|
||||
if (!isint(rept_loop)) {
|
||||
rept_loop = 0;
|
||||
rept_loop = 10000;
|
||||
}
|
||||
if (rept_loop < 1) {
|
||||
quit "rept_loop must be an integer > 0";
|
||||
}
|
||||
if (!isint(p_elim)) {
|
||||
p_elim = 17;
|
||||
}
|
||||
if (p_elim < 3) {
|
||||
quit "p_elim must be an integer > 2 (try 13 or 17)";
|
||||
}
|
||||
|
||||
/*
|
||||
* declare our global values
|
||||
*/
|
||||
Q = 4*pfact(p_elim);
|
||||
hcount = 2;
|
||||
/* allocate the h difference array */
|
||||
for (i=2; i <= p_elim; i = nextcand(i)) {
|
||||
hcount *= (i-1);
|
||||
}
|
||||
local mat hset[hcount+1];
|
||||
|
||||
/*
|
||||
* load the hset[] difference array
|
||||
*/
|
||||
{
|
||||
local x; /* h*n+1 mod 8 */
|
||||
local h; /* potential h value */
|
||||
local last_h; /* previous valid h value */
|
||||
|
||||
last_h = 0;
|
||||
for (i=0,h=0; h < Q; ++h) {
|
||||
if (gcd(h*n+1,Q) == 1) {
|
||||
x = (h*n+1) % 8;
|
||||
if (x == 1 || x == 7) {
|
||||
hset[i++] = (h-last_h) * n;
|
||||
last_h = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
hset[hcount] = Q*n - last_h*n;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup
|
||||
*/
|
||||
step2 = 2*n;
|
||||
step6 = 6*n;
|
||||
k = start_k - 1;
|
||||
q = 2*k*n+1;
|
||||
/* step2 to the first factor candidate */
|
||||
do {
|
||||
q += step2;
|
||||
mod8 = mod(q,8);
|
||||
++k;
|
||||
} while (mod8 != 1 && mod8 != 7);
|
||||
|
||||
/*
|
||||
* At this point we are at either at the first or second
|
||||
* of two consequtive factor candidates depending on if
|
||||
* the next to k values are 1 and 7 mod 8.
|
||||
*
|
||||
* The loops below assume that we will test, bump k by 1
|
||||
* (move to the 2nd consequtive factor candidate), test and
|
||||
* bump k by 3 (move to the first of the next consequtive
|
||||
* factor candidate pair).
|
||||
* determine the next g and hset[] index (hindx) values such that:
|
||||
*
|
||||
* In order to prepair, we need to move to the first of
|
||||
* a consequtive factor candidate pair. If we happen to
|
||||
* be on a the 2nd of a pair, we will test it outside
|
||||
* of the loop and bump to the first of the next pair.
|
||||
* 2*start_k <= (Q*g + hset[hindx])
|
||||
*
|
||||
* and (Q*g + hset[hindx]) is a minimum and where:
|
||||
*
|
||||
* Q = (4 * pfact(of some reasonable integer))
|
||||
* g = (some integer) (hset[] cycle number)
|
||||
*
|
||||
* We also compute 'q', the next test candidate.
|
||||
*/
|
||||
mod8 = mod(q+step2,8);
|
||||
if (mod8 != 1 && mod8 != 7) {
|
||||
/*
|
||||
* q is the 2nd of a consequtive factor candidate pair
|
||||
* so we test q now and bump k by 3.
|
||||
*/
|
||||
if (pmod(2,n,q) == 1) {
|
||||
/* q was a factor afterall, no need to do more! */
|
||||
return q;
|
||||
}
|
||||
q += step6;
|
||||
k += 3;
|
||||
g = (2*start_k) // Q;
|
||||
tmp = 2*start_k - Q*g;
|
||||
for (tmp2=0, hindx=0;
|
||||
hindx < hcount && (tmp2 += hset[hindx]/n) < tmp;
|
||||
++hindx) {
|
||||
}
|
||||
if (hindx == hcount) {
|
||||
/* we are beyond the end of a hset[] cycle, start at the next */
|
||||
++g;
|
||||
hindx = 0;
|
||||
tmp2 = hset[0]/n;
|
||||
}
|
||||
q = (Q*g + tmp2)*n + 1;
|
||||
|
||||
/*
|
||||
* look for a factor
|
||||
*
|
||||
* We ignore factors that themselves are divisible by a prime <=
|
||||
* some small prime p.
|
||||
*
|
||||
* This process is guaranteed to find the smallest factor
|
||||
* of 2^n-1. A smallest factor of 2^n-1 must be prime, otherwise
|
||||
* the divisors of that factor would also be factors of 2^n-1.
|
||||
* Thus we know that if a test factor itself is not prime, it
|
||||
* cannot be the smallest factor of 2^n-1.
|
||||
*
|
||||
* Eliminating all non-prime test factors would take too long.
|
||||
* However we can eliminate 80.81% of the test factors
|
||||
* by not using test factors that are divisible by a prime <= 17.
|
||||
*/
|
||||
loop = k;
|
||||
while (pmod(2,n,q) != 1) {
|
||||
|
||||
if (pmod(2,n,q) == 1) {
|
||||
return q;
|
||||
} else {
|
||||
/* report this loop */
|
||||
printf("at 2*%d*%d+1, cpu: %f\n",
|
||||
(q-1)/(2*n), n, runtime());
|
||||
fflush(files(1));
|
||||
loop = 0;
|
||||
}
|
||||
do {
|
||||
/*
|
||||
* determine if we need to report
|
||||
*
|
||||
* NOTE: (q-1)/(2*n) is the k value from 2*k*n + 1.
|
||||
*/
|
||||
if (rept_loop > 0) {
|
||||
if (rept_loop <= ++loop) {
|
||||
/* report this loop */
|
||||
printf("at 2*%d*%d+1, cpu: %f\n",
|
||||
k, n, runtime());
|
||||
fflush(files(1));
|
||||
loop = 0;
|
||||
}
|
||||
k += 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* 1st of a consequtive factor candidate pair is not
|
||||
* a factor, try the 2nd of that pair
|
||||
*/
|
||||
q += step2;
|
||||
if (pmod(2,n,q) == 1) {
|
||||
break; /* factor found */
|
||||
if (rept_loop <= ++loop) {
|
||||
/* report this loop */
|
||||
printf("at 2*%d*%d+1, cpu: %f\n",
|
||||
(q-1)/(2*n), n, runtime());
|
||||
fflush(files(1));
|
||||
loop = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 2nd of a consequtive factor candidate pair is not
|
||||
* a factor, try the next pair
|
||||
* skip if divisable by a prime <= 449
|
||||
*
|
||||
* The value 281 was determined by timing loops
|
||||
* which found that 281 was at or near the
|
||||
* minimum time to factor 2^(2^127-1)-1.
|
||||
*
|
||||
* The addition of the do { ... } while (factor(q, 449)>1);
|
||||
* loop reduced the factoring loop time (36504 k values with
|
||||
* the hset[] initialization time removed) from 25.69 sec to
|
||||
* 15.62 sec of CPU time on a 200Mhz r4k.
|
||||
*/
|
||||
q += step6;
|
||||
}
|
||||
do {
|
||||
/*
|
||||
* determine the next factor candidate
|
||||
*/
|
||||
q += hset[++hindx];
|
||||
if (hindx >= hcount) {
|
||||
hindx = 0;
|
||||
/*
|
||||
* if we cared about g,
|
||||
* then we wound ++g here too
|
||||
*/
|
||||
}
|
||||
} while (factor(q, 449) > 1);
|
||||
} while (pmod(2,n,q) != 1);
|
||||
|
||||
/*
|
||||
* return the factor found
|
||||
*
|
||||
* q is a factor of (2^n)-1
|
||||
*/
|
||||
return q;
|
||||
}
|
||||
|
||||
global lib_debug;
|
||||
if (lib_debug >= 0) {
|
||||
print "mfactor(n [, start_k [, rept_loop]])"
|
||||
if (config("lib_debug") >= 0) {
|
||||
print "mfactor(n [, start_k=1 [, rept_loop=10000 [, p_elim=17]]])"
|
||||
}
|
||||
|
Reference in New Issue
Block a user