Primorial Program

Home Observation Primorial Program Special Classes

Below is a short program that finds prime numbers that exist near a primorial. The property that only certain numbers near a primorial can be prime allows a simple program to be written that finds these primes by only testing values known not to be composite.  It uses the GMP library.

Some samples runs of this program have generated primes 4-10 times more often than sequential testing of each number.

/////////////////////////////////////////////////////////////////////////////
// findprp - find a probable prime near a primorial.
//
// This command can be called as follows:
//
// findprp #  to find all probable primes above and near the primorial n#
// findprp #-1 to find all probable primes below and near the primorial n#
// findprp *# to find probable primes near the multiple of the primorial m*n#
//
// Primality checking is done using the Miller-Rabin algorithm.
//
// You can also start the search at a given offset by executing the command 
// witha positive or negative offset.  This allows you to start from a given
// point if the values have already been tested.
//
// For example: 'findprp 27509#-31253' will find all primes starting at that 
// and working down.
//
// This program requires the GMP library (http://www.gmplib.org) and can be 
// number compiled:
//
//	cc -o findprp findprp.c -lgmp
//
// Progress of the search will be sent to standard error.  When a probable
// prime is found, it will be send to standard output.  It will contain the
// number followed by a comma and the number of decimal digits in the number.
//
// Copyright, 2008, Paul Schmidt.  Can be used for research and personal use.
/////////////////////////////////////////////////////////////////////////////

#include 
#include 
#include 
#include 

void print_num(
FILE *f, 
unsigned long mult, 
unsigned long p, 
int sign, 
unsigned long c)
{
  if (mult != 1)
    fprintf(f, "%d*", mult);
  fprintf(f, "%d#", p);
  if (sign)
    fprintf(f, "+");
  else
    fprintf(f, "-");
  fprintf(f, "%d", c);
}

main (int argc, char *argv[])
{
  char *progname = argv[0];
  unsigned long p_ui;
  unsigned long pn;
  unsigned long pn1;
  unsigned long from = 1;
  unsigned long mult = 1;
  int above = 1;
  mpz_t primorial;
  mpz_init(primorial);
  mpz_t p;
  mpz_init(p);

  
  if (argc < 2)
  {
    fprintf(stderr, "Usage: %s [multiplier]*+/-[start]\n", progname);
    exit(1);
  }

  if (strchr(argv[1],'*'))
  {
    if (strchr(argv[1],'+'))
      sscanf(argv[1], "%U#*%U+%U", &mult, &pn, &from);
    else if (strchr(argv[1],'-'))
    {
      sscanf(argv[1], "%U#*%U-%U", &mult, &pn, &from);
      above = 0;
    }
    else
      sscanf(argv[1], "%U#*%U", &mult, &pn);
  }
  else
  {
    if (strchr(argv[1],'+'))
      sscanf(argv[1], "%U#+%U", &pn, &from);
    else if (strchr(argv[1],'-'))
    {
      sscanf(argv[1], "%U#-%U", &pn, &from);
      above = -1;
    }
    else
      sscanf(argv[1], "%U#", &pn);
  }

  mpz_set_ui(primorial, 2);
  for (mpz_set_ui(p, 3);  mpz_cmp_ui(p, pn) <= 0;  mpz_nextprime(p, p))
  {
    mpz_mul(primorial, primorial, p);
    p_ui = mpz_get_ui(p);
  }

  pn = p_ui;
  pn1 = mpz_get_ui(p);

  mpz_t number;
  mpz_init2(number, mpz_sizeinbase(primorial,2) + 32);
  mpz_mul_ui(number, primorial, mult);

  mpz_t tmp;
  mpz_init2(tmp, mpz_sizeinbase(number,2) + 1);

  mpz_t to;
  mpz_init_set_ui(to, pn1);
  mpz_mul_ui(to, to, pn1); 

  for (mpz_set_ui(p, from); mpz_cmp(p, to) < 0; mpz_nextprime(p, p))
  {
    fprintf(stderr, "\nTesting "); 
    print_num(stderr, mult, pn, above, mpz_get_ui(p)); 
    if (above)
      mpz_add(tmp, number, p);
    else
      mpz_sub(tmp, number, p);
    if (mpz_millerrabin(tmp, 5))
    {
      print_num(stdout, mult, pn, above, mpz_get_ui(p));
      fprintf(stdout, ",%U\n", mpz_sizeinbase(tmp, 10));
      fflush(stdout);
      fprintf(stderr, " is a prp!");
    }
    if (mpz_cmp_ui(p, 1) == 0)
      mpz_set_ui(p, pn1);
  }

  mpz_clear(primorial);
  mpz_clear(number);
  mpz_clear(p);
  mpz_clear(tmp);
}

Conclusion

This program quickly starts testing for probable primes after eliminating many composites from a range.  This means you are more likely to find a probable prime quickly.  There is no overhead in memory or disk space for extra tables.  The only memory used is to store the number that will be tested and the primorial itself.

Although this algorithm has many advantages, another simple algorithm that could run faster is one that would take a range of numbers (e.g. 0 - 2^32) at any arbitrarily large number, sieve that range with all primes up to the upper limit, then test those numbers that did not get set to composite.  The sieve may take some time, as you will need to calculate the remainder for each prime.  The result of the sieve will also need to be stored.  The set of numbers left after the sieve will be less than set used in the above program if the upper limit is high enough.

Links

If you have any questions or comments, pleas email me at paul@schmidthouse.org.