home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 3 / goldfish_volume_3.bin / files / dev / c / cweb / examples / primes.ch < prev    next >
Encoding:
Text File  |  1994-11-09  |  11.2 KB  |  344 lines

  1. Dijkstra's and Knuth's "primes" programs calculate the first 1000 prime
  2. numbers.  Now that's just greasy kids' stuff, so we want more...
  3.  
  4. @x l.24
  5. \def\title{PRIMES (C Version 1.1)}
  6. @y
  7. \def\title{PRIMES (C Version 1.2)}
  8. @z
  9.  
  10. @x l.28
  11.   \centerline{(C Version 1.1)}
  12. @y
  13.   \centerline{(C Version 1.2)}
  14. @z
  15.  
  16. @x l.46
  17. Dijkstra's program prints a table of the first thousand prime numbers. We
  18. @y
  19. Dijkstra's program prints a table of the first thousand prime numbers, but
  20. here we want significantly more, i.e., we calculate a table of the first
  21. million prime numbers (this may take some time on slow machines!). We
  22. @z
  23.  
  24. @x l.63
  25. @<Program to print the first thousand prime numbers@>
  26. @y
  27. @<Program to print the first million prime numbers@>
  28. @z
  29.  
  30. @x l.66
  31. result of the program will be to produce a list of the first thousand prime
  32. numbers, and this list will appear on the |stdout| file.
  33. @y
  34. result of the program will be to produce a list of the first million prime
  35. numbers, and this list will appear in a (most certainly system dependent)
  36. binary file.
  37. @z
  38.  
  39. @x l.69
  40. Since there is no input, we declare the value |MM==1000| as a compile-time
  41. @y
  42. Since there is no input, we declare the value |MM==1000000| as a compile-time
  43. @z
  44.  
  45. @x l.79
  46. @d MM    1000
  47. @y
  48. @d MM    1000000
  49. @z
  50.  
  51. @x l.84
  52. #include <stdio.h>
  53. @y
  54. #include <stdio.h>
  55. #include <stdlib.h>
  56. @h
  57. @z
  58.  
  59. @x l.109
  60.    @<Fill table |p| with the first |MM| prime numbers@>@;
  61.    @<Print table |p|                                 @>@;
  62. @y
  63.    @<Allocate memory for tables |p| and |mult|       @>@;
  64.    @<Fill table |p| with the first |MM| prime numbers@>@;
  65.    @<Print table |p|                                 @>@;
  66.    @<Free tables |p| and |mult|                      @>@;
  67. @z
  68.  
  69. @x l.137
  70.    int p[MM]; /* the first |MM| prime numbers, in increasing order */
  71. @y
  72.    long *p; /* the first |MM| prime numbers, in increasing order */
  73. @z
  74.  
  75. @x l.146
  76. Since |p| is simply an array of integers, there is little difficulty in
  77. printing the output, except that we need to decide upon a suitable output
  78. format. Let us print the table on separate pages, with |RR| rows and |CC|
  79. columns per page, where every column is |WW| character positions wide. In
  80. this case we shall choose |RR==50|, |CC==5|, and |WW==10|, so that
  81. the first 1000~primes will appear on four pages. The program will not assume
  82. that |MM| is an exact multiple of |RR@t${}\times{}$@>CC|.
  83. @^output format@>
  84. @^Differences between \PASCAL/ and \CEE/@>
  85.  
  86. @d RR 50 /* this many rows will be on each page in the output         */
  87. @d CC  5 /* this many columns will be on each page in the output      */
  88. @d WW 10 /* this many character positions will be used in each column */
  89.  
  90. @ In order to keep this program reasonably free of notations that are
  91. uniquely \CEE/esque, \[and in order to illustrate more of the facilities of
  92. \.{CWEB},\] a few macro definitions for low-level output instructions are
  93. introduced here. All of the output-oriented commands in the remainder of
  94. the program will be stated in terms of five simple primitives called
  95. |print_string|, |print_integer|, |print_entry|, |new_line|, and |new_page|.
  96.  
  97. \[Sections of a \.{CWEB} program are allowed to contain {\it macro
  98. definitions} between the opening comments and the closing program text. The
  99. general format for each section is actually tripartite: commentary, then
  100. definitions, then program. Any of the three parts may be absent; for
  101. example, the present section contains no program text.\]
  102.  
  103. \[Simple macros simply substitute a bit of \CEE/ code for an identifier.
  104. Parametric macros are similar, but they also substitute an argument
  105. wherever `A' occurs in the macro definition. (You may \#|define| macros with
  106. more than just one parameter in \CEE/.) The first three macro definitions
  107. here are parametric; the other two are simple. (I am using |fputs| in order
  108. to get rid of the surplus `new line' character inserted by |puts|, and I am
  109. using |putc| instead of |putchar| for consistency in notation.)\]
  110. @^Differences between \PASCAL/ and \CEE/@>
  111.  
  112. @d print_string(A)
  113.    fputs(A,stdout) /* put a given string into the |stdout| file */
  114. @d print_integer(A)
  115.    printf("%d",A) /* put a given integer into the |stdout| file, in decimal
  116.    notation, using only as many digit positions as necessary */
  117. @d print_entry(A)
  118.    printf("%*d",WW,A) /* like |print_integer|, but |WW| character positions
  119.    are filled, inserting blanks at the left */
  120. @d new_line putc('\n',stdout); fflush(stdout)
  121.    /* advance to a new line in the |stdout| file */
  122. @d new_page putc('\f',stdout); fflush(stdout)
  123.    /* advance to a new page in the |stdout| file */
  124.  
  125. @ Several variables are needed to govern the output process. When we begin
  126. to print a new page, the variable |page_number| will be the ordinal number
  127. of that page, and |page_offset| will be such that |p[page_offset-1]| is the
  128. first prime to be printed. Similarly, |p[row_offset-1]| will be the first
  129. prime in a given row.
  130.  
  131. \[Notice the notation `$\mathrel+\E$' below; this indicates that the present
  132. section has the same name as a previous section, so the program text will
  133. be appended to some text that was previously specified.\]
  134.  
  135. @<Variables of the program@>=
  136.    int page_number;
  137.       /* one more than the number of pages printed so far */
  138.    int page_offset;
  139.       /* index into |p| for the first entry on the current page */
  140.    int row_offset;
  141.       /* index into |p| for the first entry in the current row */
  142.    int c;
  143.       /* runs through the columns in a row (|0@t${}\ldots{}$@>CC|) */
  144.  
  145. @ Now that appropriate auxiliary variables have been introduced, the
  146. process of outputting table |p| almost writes itself.
  147.  
  148. @<Print table |p|@>={
  149.    page_number = page_offset = 1;
  150.    while(page_offset <= MM) {
  151.       @<Output a page of answers@>@;
  152.       page_number++;
  153.       page_offset += RR*CC;
  154.       }
  155.    }
  156.  
  157. @ A simple heading is printed at the top of each page.
  158. @^output format@>
  159. @^page headings@>
  160. @<Output a page of answers@>={
  161.    print_string("The First ");@+               print_integer(MM);
  162.    print_string(" Prime Numbers --- Page ");@+ print_integer(page_number);
  163.    new_line;@+ new_line; /* there's a blank line after the heading */
  164.    for(row_offset = page_offset; row_offset <= page_offset + RR - 1;
  165.       row_offset++)
  166.       @<Output a line of answers@>@;
  167.    new_page;
  168.    }
  169.  
  170. @ The first row will contain
  171. $$
  172.   p[1-1],\thinspace p[1+\.{RR}-1],\thinspace
  173.   p[1+2\cdot\.{RR}-1],\thinspace \ldots;
  174. $$
  175. a similar pattern holds for each value of the |row_offset|.
  176.  
  177. @<Output a line of answers@>={
  178.    for(c=0; c<=CC-1; c++) {
  179.       if(row_offset+c*RR <= MM)
  180.          print_entry(p[row_offset + c*RR -1]);
  181.       }
  182.    new_line;
  183.    }
  184. @y
  185. One million integers in text format accumulate to a great mass of paper if
  186. we used the original output format (4000~pages!), so here we do something
  187. very simple (breaking every unwritten law of \CEE/ programming in doing so): 
  188. we write the binary representation of |p| to a file that can be processed
  189. later by suitable tools.  Our first intension in this patch is to ``do the
  190. calculations and save the results.''  Unfortunately, the resulting binary
  191. file is heavily dependent on the hardware ``primes'' is running on, so
  192. don't expect the contents of {\tt primes.out} to be portable in any sense.
  193.  
  194. @ We don't need a lot of variables to create the output, a |FILE| pointer
  195. will suffice.  In a quiet hour, an analyzing tool can then implement
  196. whatever ``real'' output format is suitable, either displaying all primes
  197. or just picking at some of them.  A very simple program for the latter
  198. approach is included right before the index of this source.
  199.  
  200. @<Variables of the program@>=
  201.    FILE *fp;
  202.  
  203. @ The process of outputting table |p| is a trivial pursuit, although I'm
  204. absolutely sure this will crash some compilers.  So, what!
  205.  
  206. @<Print table |p|@>=
  207.    if(fp=fopen("primes.out","wb")) {
  208.       fwrite(p,sizeof(long),MM,fp);
  209.       fclose(fp);
  210.       }
  211. @z
  212.  
  213. @x l.266
  214.    while(k < MM) {
  215.       @<Increase |j| until it is the next prime number@>@;
  216.       k++;@+ p[k-1] = j;
  217.       }
  218. @y
  219.    while(k < MM) {
  220.       @<Increase |j| until it is the next prime number@>@;
  221.       k++;@+ p[k-1] = j;
  222.       if(k%1000==0) {
  223.          putchar('.'); /* Give some progress indication and
  224.             also a chance to |break| */
  225.          fflush(stdout);
  226.          }
  227.       }
  228.    putchar('\n'); fflush(stdout);
  229. @z
  230.  
  231. @x l.275
  232.    int j; /* all primes ${}\leq j$ are in table |p|                    */
  233.    int k; /* this many primes are in table |p| (|0@t${}\ldots{}$@>MM|) */
  234. @y
  235.    long j; /* all primes ${}\leq j$ are in table |p|                    */
  236.    long k; /* this many primes are in table |p| (|0@t${}\ldots{}$@>MM|) */
  237. @z
  238.  
  239. @x l.340
  240.    int ord; /* the smallest index ${}\geq2$ such that $p^2_{ord}>j$ */
  241.    int square; /* |square|${}=p^2_{ord}$ */
  242. @y
  243.    long ord; /* the smallest index ${}\geq2$ such that $p^2_{ord}>j$ */
  244.    long square; /* |square|${}=p^2_{ord}$ */
  245. @z
  246.  
  247. @x l.348
  248. exceeds 30 when |MM==1000|.
  249.  
  250. @d ORD_MAX 30 /* $p^2_{ord\_max}$ must exceed $p_M$ */
  251. @y
  252. exceeds 3000 when |MM==1000000|.
  253.  
  254. @d ORD_MAX 3000 /* $p^2_{ord\_max}$ must exceed $p_M$ */
  255. @z
  256.  
  257. @x l.391
  258.    int n; /* runs from 2 to |ord| when testing divisibility */
  259. @y
  260.    long n; /* runs from 2 to |ord| when testing divisibility */
  261. @z
  262.  
  263. @x l.413
  264.    int mult[ORD_MAX]; /* runs through multiples of primes */
  265. @y
  266.    long *mult; /* runs through multiples of primes */
  267. @z
  268.  
  269. @x l.437
  270. @* For further reading. Here is a very short list of literature that has
  271. @y
  272. @* Memory allocation.  When using the standard form of this program with
  273. very high values of |MM|, e.g., |1000000|, all internal memory is loaded
  274. on the stack and this amounts to more than 4~MB of {\mc RAM}.  To avoid
  275. system crashes due to stack overflow, the two internal arrays are
  276. allocated dynamically at run-time.  If your compiler can't handle
  277. this much of memory in one block, change the system.
  278.  
  279. @s type long
  280.  
  281. @d allocate_memory(object,size,type)
  282.    if(!(object=(type *)malloc((size)*sizeof(type))))
  283.       exit(EXIT_FAILURE);
  284.  
  285. @<Alloc...@>=
  286.    allocate_memory(p,MM,long);
  287.    allocate_memory(mult,ORD_MAX,long);
  288.  
  289. @ After the calculations are done and the output is written the memory is
  290. freed in reverse order.  This isn't really necessary, but it's nicer.
  291.  
  292. @d free_memory(object)
  293.    if(object)
  294.       free(object);
  295.  
  296. @<Free...@>=
  297.    free_memory(mult);
  298.    free_memory(p);
  299.  
  300. @* Analyzing the results.  Here is a very simple tool to read {\tt
  301. primes.out} and pick at certain prime numbers on user's request.  Again I
  302. have to warn about possible problems with brain-dead compilers.  This code
  303. works for me, but I expect there will be problems on other systems.
  304.  
  305. @(primereader.c@>=
  306. #include <stdio.h>
  307. #include <stdlib.h>
  308. @h
  309.  
  310. void main(void)
  311.    {
  312.    FILE *fp;
  313.    long *p,i;
  314.  
  315.    if((fp=fopen("primes.out","rb")) && (p=(long *)malloc(MM*sizeof(long)))) {
  316.       fread(p,sizeof(long),MM,fp);
  317.       fclose(fp);
  318.       @<Choose primes at random@>@;
  319.       free(p);
  320.       }
  321.    }
  322.  
  323. @ @<Choose primes at random@>=
  324.    while(1) {
  325.       do {
  326.          fputs("Gimme a number: ",stdout); fflush(stdout);
  327.          scanf("%ld",&i);
  328.          } while((1L>i)||(i>MM)); /* |i| must be a legal index value */
  329.       switch(i) {
  330.       case 1:
  331.          fputs("The first ",stdout); break;
  332.       case 2:
  333.          fputs("The second ",stdout); break;
  334.       case 3:
  335.          fputs("The third ",stdout); break;
  336.       default:
  337.          printf("The %dth ",i);
  338.          }
  339.       printf("prime number is %d.\n\n",p[i-1]);
  340.       }
  341.  
  342. @* For further reading. Here is a very short list of literature that has
  343. @z
  344.