/* Look for primes of the form Rp = (b^p+-1)/(b+-1). Such primes have p ones in their base-b representation. If p has factors, so does Rp. We use GMP's native operations for pseudoprime tests (Miller-Rabin), as it seems difficult to adopt Lucas' test for these numbers. In order to avoid calling the expensive Miller-Rabin tests in some cases, we make a lame attempt to find small factors. Such factors are of the form 2kp+1, and must be congruent to 1, 3, 9, 13, 27, 31, 37 or 39 mod 40. */ #include #include #include #include #include #include #include "gmp.h" #ifndef BASE #define BASE 10 #endif #if defined (REVERSE_REPUNIT) && REVERSE_REPUNIT - 0 != 0 #undef REVERSE_REPUNIT #define REVERSE_REPUNIT 1 #else #define REVERSE_REPUNIT 0 #endif #if REVERSE_REPUNIT #define PLUSMINUS + #else #define PLUSMINUS - #endif #if __GNUC__ typedef unsigned int UQItype __attribute__ ((mode (QI))); typedef unsigned int UHItype __attribute__ ((mode (QI))); typedef int SItype __attribute__ ((mode (SI))); typedef unsigned int USItype __attribute__ ((mode (SI))); typedef int DItype __attribute__ ((mode (DI))); typedef unsigned int UDItype __attribute__ ((mode (DI))); #else typedef unsigned char UQItype; typedef unsigned short int UHItype; typedef int SItype; typedef unsigned int USItype; typedef long long int DItype; typedef long long unsigned int UDItype; #endif #if ! defined (ARITH) #error "need to define ARITH to 32 or 64" #endif #if ARITH == 64 typedef UDItype UWtype; typedef DItype SWtype; typedef UHItype UHWtype; #define W_TYPE_SIZE 64 #endif #if ARITH == 32 typedef USItype UWtype; typedef SItype SWtype; typedef UHItype UHWtype; #define W_TYPE_SIZE 32 #endif #include "longlong.h" #if defined (_MIPS_SIM) #if _MIPS_SIM == _ABIN32 typedef unsigned long long word; #define DEFINED_word #endif #endif #ifndef DEFINED_word typedef unsigned long word; #endif char tab40[] = {0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0, 0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,1}; char tab105[] = {0,1,1,0,1,0,0,0,1,0,0,1,0,1,0,0,1,1,0,1,0, 0,1,1,0,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1, 0,1,1,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,1,1, 0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,0,1,1, 0,0,1,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,0,1,1}; int powmod (); struct proc_info { pid_t pid; int fd; unsigned int p; }; struct proc_info *proc_info; int max_n_processes = 1; void start_proc (); unsigned int check_one (); unsigned int mpz_ones_composite_p (); unsigned int findfactor (); int isprime (); int main (int argc, char **argv) { unsigned int from, to; int n_processes; int i; unsigned int p; char out_file[20]; from = strtoul (argv[1], 0, 0); to = strtoul (argv[2], 0, 0); if (argc == 4) max_n_processes = strtol (argv[3], 0, 0); sprintf (out_file, "repunit%d.out", BASE); unlink (out_file); n_processes = 0; proc_info = malloc (max_n_processes * sizeof *proc_info); for (i = 0; i < max_n_processes; i++) proc_info[i].pid = -1; p = from; while (1) { pid_t pid; int status; /* Start more processes if we don't already have enough. */ while (n_processes != max_n_processes) { #ifdef NOT_JUST_PRIME_EXPONENTS if ((p & 1) == 0) p += 1; #else while (! isprime (p)) p += 1; #endif if (p > to) break; start_proc (p); n_processes++; p += 1; } /* We have the desired # of processes. Wait for the first one to terminate and store its result. */ #ifdef NOFORK if (n_processes == 0) break; #else pid = wait (&status); if (pid == -1) break; if (! WIFEXITED (status)) { fprintf (stderr, "subprocess was killed (signal %d)\n", WTERMSIG (status)); kill (0, WTERMSIG (status)); } #endif for (i = 0; i < max_n_processes; i++) { #ifndef NOFORK if (proc_info[i].pid == pid) #endif { char buf[11]; FILE *ofs; read (proc_info[i].fd, buf, 10); close (proc_info[i].fd); ofs = fopen (out_file, "a+"); fprintf (ofs, "%u %s\n", proc_info[i].p, buf); fclose (ofs); proc_info[i].pid = -1; /* mark slot as free */ n_processes--; } } } exit (0); } void start_proc (unsigned int p) { int channel[2]; pid_t pid; int i; for (i = 0; i < max_n_processes; i++) { if (proc_info[i].pid == -1) break; } pipe (channel); #ifdef NOFORK for (pid = 1; pid != (pid_t) -1; pid--) #else pid = fork (); #endif if (pid != 0) { /* Parent. */ #if DEBUG fprintf (stderr, "starting: %d (%d) pid=%d\n", p, i, pid); #endif #ifndef NOFORK close (channel[1]); #endif proc_info[i].fd = channel[0]; proc_info[i].pid = pid; proc_info[i].p = p; } else { /* Child. */ unsigned int factor; char buf[11]; #ifndef NOFORK close (channel[0]); #endif factor = check_one (p); if (factor == 0) sprintf (buf, "y"); else if (factor == (unsigned int) -1) sprintf (buf, "n"); else sprintf (buf, "%u", factor); write (channel[1], buf, strlen (buf) + 1); close (channel[1]); #ifndef NOFORK _exit (0); #endif } } unsigned int check_one (unsigned int p) { int k; unsigned int klimit; unsigned long long int k2; mpz_t t; int result; mpz_init (t); #if REVERSE_REPUNIT mpz_ui_pow_ui (t, (unsigned long int) (BASE), (unsigned long int) p); mpz_add_ui (t, t, 1L); mpz_tdiv_q_ui (t, t, (unsigned long int) ((BASE) + 1)); #else mpz_ui_pow_ui (t, (unsigned long int) (BASE), (unsigned long int) p); mpz_tdiv_q_ui (t, t, (unsigned long int) ((BASE) - 1)); #endif /* Set the factoring search limit approximately propotional to the time we will need for testing primality. */ #ifdef FACTOR_AGGRESSIVELY k2 = p * p; if (k2 != (unsigned int) k2) klimit = (unsigned int) ~0; else { klimit = k2; if (klimit < 10000000) klimit = 10000000; } #else k2 = p * p / 5; if (k2 != (unsigned int) k2) klimit = (unsigned int) ~0; else { klimit = k2; if (klimit < 100000) klimit = 100000; } #endif k = findfactor (p, klimit); if (k) { mpz_t f; mpz_init (f); /* Check is the found factor is actually equal to the checked number. In that case we really have a prime (not even a prp). */ mpz_set_ui (f, (unsigned long int) k); mpz_mul_ui (f, f, (unsigned long int) 2 * p); mpz_add_ui (f, f, 1L); if (mpz_cmp (t, f) == 0) k = 0; /* prime/prp */ mpz_clear (f); mpz_clear (t); return k; } #if NOPRIMETEST mpz_clear (t); return (unsigned int) -1; #endif if (mpz_cmp_ui (t, 10000) < 0) result = isprime ((unsigned int) mpz_get_ui (t)); else { result = fermat_pseudoprime ((BASE) == 2 ? 3 : 2, t); if (result != 0) result = mpz_probab_prime_p (t, 3); } mpz_clear (t); return result != 0 ? 0 : (unsigned int) -1; } unsigned int findfactor (unsigned int p, unsigned int klimit) { static word pows[ARITH + 1]; static int digits_per_word = 0; if (digits_per_word == 0) { word x = 1; word xx; int i; for (i = 0;; i++) { pows[i] = x; xx = x * BASE; if (xx / BASE != x) { digits_per_word = i; break; } x = xx; } } { unsigned int k; unsigned int pprev, pprem; int cnt; word powinit; pprev = 0; pprem = p; cnt = 0; while (pprem > digits_per_word) { pprev = (pprev << 1) | (pprem & 1); pprem >>= 1; cnt++; } powinit = pows[pprem]; /* Look for k such that 2kp+1 | (b^p+1)/(b+1). */ for (k = 1; k < klimit; k++) { #if ARITH == 64 word d; int r; d = (word) 2 * p * k + 1; #if BASE == 10 && ! REVERSE_REPUNIT if (! tab40[d % 40]) continue; #endif if (! tab105[d % 105] && d > 7) continue; r = powmod (pprev, powinit, cnt, d); /* If we found a factor, return it. But watch out for factors that just divide BASE+-1. */ if (r != 0 && (BASE PLUSMINUS 1) % d != 0) return k; #endif #if ARITH == 32 word dh, dl; int r; word i, dummy; umul_ppmm (dh, dl, k, 2 * p); add_ssaaaa (dh, dl, dh, dl, 0, 1); #if BASE == 10 && ! REVERSE_REPUNIT if (UDIV_NEEDS_NORMALIZATION) { word xh, xl; xh = dh % 40; xh = (xh << 26) | (dl >> 6); xl = dl << 26; udiv_qrnnd (dummy, i, xh, xl, 40 << 26); i >>= 26; } else udiv_qrnnd (dummy, i, dh % 40, dl, 40); if (! tab40[i]) continue; #endif if (UDIV_NEEDS_NORMALIZATION) { word xh, xl; xh = dh % 105; xh = (xh << 25) | (dl >> 7); xl = dl << 25; udiv_qrnnd (dummy, i, xh, xl, 105 << 25); i >>= 25; } else udiv_qrnnd (dummy, i, dh % 105, dl, 105); if (! tab105[i] && (dh != 0 || dl > 7)) continue; r = powmod (pprev, powinit, cnt, dh, dl); if (r != 0 && (dh != 0 || (BASE PLUSMINUS 1) % dl != 0)) return k; #endif } return 0; } } #if ARITH == 64 #ifndef __alpha word __mpn_invert_normalized_limb (word d) { word di, dummy; /* Special case for DIVISOR_LIMB == 100...000. */ if (d << 1 == 0) di = ~(word) 0; else udiv_qrnnd (di, dummy, -d, 0, d); return di; } #endif int powmod (unsigned int pprev, word x, int cnt, word d) { int i; word s, sh, sl; word di; word dummy; int nc; count_leading_zeros (nc, d); di = __mpn_invert_normalized_limb (d << nc); s = x % d; for (i = cnt; i != 0; i--) { umul_ppmm (sh, sl, s, s << nc); udiv_qrnnd_preinv (dummy, s, sh, sl, d << nc, di); s >>= nc; if ((pprev & 1) != 0) { s *= BASE; if (BASE >= 256) fprintf (stderr, "error cannot handle BASE >= 256\n"); if (BASE >= 128 && s >= 128*d) s -= 128*d; if (BASE >= 64 && s >= 64*d) s -= 64*d; if (BASE >= 32 && s >= 32*d) s -= 32*d; if (BASE >= 16 && s >= 16*d) s -= 16*d; if (BASE >= 8 && s >= 8*d) s -= 8*d; if (BASE >= 4 && s >= 4*d) s -= 4*d; if (s >= 2*d) s -= 2*d; if (s >= d) s -= d; } pprev >>= 1; } if (REVERSE_REPUNIT) s = d - s; return s == 1; } #endif #if ARITH == 32 int powmod (unsigned int pprev, word x, int cnt, word dh, word dl) { int i; word sh, sl; word rh, rl; sl = x; if (dh == 0) sl %= dl; sh = 0; for (i = cnt; i != 0; i--) { mulmod (sh, sl, sh, sl, dh, dl, &rh, &rl); sh = rh; sl = rl; if ((pprev & 1) != 0) { mulmod (sh, sl, 0, BASE, dh, dl, &rh, &rl); sh = rh; sl = rl; } pprev >>= 1; } if (REVERSE_REPUNIT) sub_ddmmss (sh, sl, dh, dl, sh, sl); return sh == 0 && sl == 1; } #endif int isprime (unsigned int t) { unsigned int q, r, d; if (t < 3 || (t & 1) == 0) return t == 2; for (d = 3, r = 1; r != 0; d += 2) { q = t / d; r = t - q * d; if (q < d) return 1; } return 0; } int fermat_pseudoprime (unsigned int a, mpz_t t) { mpz_t tmp, az, res; int ret; mpz_init (tmp); mpz_init (res); mpz_init_set_ui (az, (unsigned long int) a); mpz_sub_ui (tmp, t, 1L); mpz_powm (res, az, tmp, t); ret = mpz_cmp_ui (res, 1L); mpz_clear (az); mpz_clear (res); mpz_clear (tmp); return ret == 0; }