primes.c

00001 /* Compute and print the prime numbers
00002    Copyright (C) 2001, 2002 Free Software Foundation, Inc.
00003    Written by Stephane Carrez (stcarrez@nerim.fr)       
00004 
00005 This file is free software; you can redistribute it and/or modify it
00006 under the terms of the GNU General Public License as published by the
00007 Free Software Foundation; either version 2, or (at your option) any
00008 later version.
00009 
00010 In addition to the permissions in the GNU General Public License, the
00011 Free Software Foundation gives you unlimited permission to link the
00012 compiled version of this file with other programs, and to distribute
00013 those programs without any restriction coming from the use of this
00014 file.  (The General Public License restrictions do apply in other
00015 respects; for example, they cover modification of the file, and
00016 distribution when not linked into another program.)
00017 
00018 This file is distributed in the hope that it will be useful, but
00019 WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; see the file COPYING.  If not, write to
00025 the Free Software Foundation, 59 Temple Place - Suite 330,
00026 Boston, MA 02111-1307, USA.  */
00027 
00054 
00055 #include <stdio.h>
00056 #include <stdarg.h>
00057 #include <sys/param.h>
00058 #include <string.h>
00059 #include <imath.h>
00060 
00061 /* The DATA_SIZE depends on your board.  The more memory, the largest
00062    the bitmap can be.  The last number we can record is 8 times the
00063    size of that bitmap (1 bit for each number).  */
00064 
00065 /* Remove the following test that reduces the bitmap.
00066    With a 32K memory system, the bitmap can contain up to
00067    224768 bits and the computation takes... a lot of time... */
00068 #if DATA_SIZE > 8192 + 512
00069 # undef DATA_SIZE
00070 # define DATA_SIZE 8192 + 512
00071 #endif
00072 
00073 /* Leave 512 or 128 bytes for stack.  */
00074 #if DATA_SIZE < 512
00075 # define MAX_PRIMES (DATA_SIZE - 128)
00076 #else
00077 # define MAX_PRIMES (DATA_SIZE - 512)
00078 #endif
00079 
00080 #define LAST_PRIME (MAX_PRIMES * 8L)
00081 
00082 /* Bitmap representing the prime numbers.  */
00083 unsigned char prime_list[MAX_PRIMES];
00084 
00085 /* Returns true if 'n' is a prime number recorded in the table.  */
00086 static inline int
00087 is_prime (unsigned long n)
00088 {
00089   unsigned short bit = (unsigned short) (n) & 0x07;
00090   
00091   return prime_list[n >> 3] & (1 << bit);
00092 }
00093 
00094 /* Record 'n' as a prime number in the table.  */
00095 static inline void
00096 set_prime (unsigned long n)
00097 {
00098   unsigned short bit = (unsigned short) (n) & 0x07;
00099 
00100   prime_list[n >> 3] |= (1 << bit);
00101 }
00102 
00103 /* Check whether 'n' is a prime number.
00104    Returns 1 if it's a prime number, 0 otherwise.  */
00105 static int
00106 check_for_prime (unsigned long n)
00107 {
00108   unsigned long i;
00109   unsigned char *p;
00110   unsigned long last_value;
00111   unsigned char small_n;
00112 
00113   small_n = (n & 0xffff0000) == 0;
00114   i = 0;
00115 
00116   /* We can stop when we have checked all prime numbers below sqrt(n).  */
00117   last_value = lsqrt (n);
00118 
00119   /* Scan the bitmap of prime numbers and divide 'n' by the corresponding
00120      prime to see if it's a multiple of it.  */
00121   p = prime_list;
00122   do
00123     {
00124       unsigned char val;
00125       
00126       val = *p++;
00127       if (val)
00128         {
00129           unsigned short j;
00130           unsigned long q;
00131 
00132           q = i;
00133           for (j = 1; val && j <= 0x80; j <<= 1, q++)
00134             {
00135               if (val & j)
00136                 {
00137                   val &= ~j;
00138 
00139                   /* Use 16-bit division if 'n' is small enough.  */
00140                   if (small_n)
00141                     {
00142                       unsigned short r;
00143 
00144                       /* 'n' is a multiple of prime 'q'.  */
00145                       r = (unsigned short) (n) % (unsigned short) (q);
00146                       if (r == 0)
00147                         return 0;
00148                     }
00149                   else
00150                     {
00151                       unsigned long r;
00152                       
00153                       r = n % q;
00154 
00155                       /* 'n' is a multiple of prime 'q'.  */
00156                       if (r == 0)
00157                         return 0;
00158                     }
00159                 }
00160             }
00161         }
00162       i += 8;
00163     }
00164   while (i < last_value);
00165   return 1;
00166 }
00167 
00168 #if 0
00169 /* Utility function that can be called from gdb to dump the prime
00170    numbers.  Do:  `call print_primes()' from gdb.  */
00171 static void
00172 print_primes (void)
00173 {
00174   long i;
00175   
00176   for (i = 0; i < LAST_PRIME; i++)
00177     if (is_prime (i))
00178       printf ("%ld\n", i);
00179 }
00180 #endif
00181 
00182 /* Set this variable to 1 if you want to print the prime numbers
00183    while they are found.  */
00184 int verbose = 0;
00185 
00186 int
00187 main ()
00188 {
00189   long i;
00190   short cnt = 0;
00191   
00192   printf ("Computing prime numbers below %ld\n",
00193           (long) LAST_PRIME);
00194   memset (prime_list, 0, sizeof (prime_list));
00195   for (i = 2; i < LAST_PRIME; i++)
00196     {
00197       if (check_for_prime (i))
00198         {
00199           set_prime (i);
00200           cnt ++;
00201           if (verbose)
00202             printf ("%ld\n", i);
00203         }
00204     }
00205   printf ("Found %ld prime numbers below %ld\n",
00206           (long) cnt, (long) LAST_PRIME);
00207 
00208   return 0;
00209 }