This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
haas:summer2017:cprog:projects:pnc2 [2017/07/07 22:54] – [Sieve of Eratosthenes (primesoe)] wedge | haas:summer2017:cprog:projects:pnc2 [2017/07/08 12:47] (current) – [Approximating array size] wedge | ||
---|---|---|---|
Line 30: | Line 30: | ||
Of note, the " | Of note, the " | ||
+ | |||
=====Optimizing the prime number calculation===== | =====Optimizing the prime number calculation===== | ||
Following will be the optimized algorithms I'd like you to implement for comparison with all the others. | Following will be the optimized algorithms I'd like you to implement for comparison with all the others. | ||
Line 35: | Line 36: | ||
For this project, please assume the following: | For this project, please assume the following: | ||
- | * you are doing all values (odds AND evens). | + | * unless otherwise specified, |
* if you exceed 64 million and get " | * if you exceed 64 million and get " | ||
* as the space-based approach to solving our prime number computation problem is fundamentally different from those we took in previous projects, you will want to look to start from scratch. Trying to reuse old code and shoehorn it into what effectively amounts to an entirely different paradigm will create a lot of problems. | * as the space-based approach to solving our prime number computation problem is fundamentally different from those we took in previous projects, you will want to look to start from scratch. Trying to reuse old code and shoehorn it into what effectively amounts to an entirely different paradigm will create a lot of problems. | ||
Line 41: | Line 42: | ||
But, the conceptual level we'll be pursuing will be the space-based equivalent of **primebrute**/ | But, the conceptual level we'll be pursuing will be the space-based equivalent of **primebrute**/ | ||
- | ====Optimizations on sieve of Eratosthenes==== | + | =====Sieve of Eratosthenes (primesoe)===== |
- | + | ||
- | ====Sieve of Eratosthenes (primesoe)==== | + | |
Your next program, and first sieve, will be the Sieve of Eratosthenes. Perhaps among the best and likely longest-known sieves, its origins date from antiquity. | Your next program, and first sieve, will be the Sieve of Eratosthenes. Perhaps among the best and likely longest-known sieves, its origins date from antiquity. | ||
Line 76: | Line 75: | ||
This is a space-constrained algorithm, therefore we will need a chunk of space to store these values. Think about what a lot of this looks like with respect to how you know how to organize data. | This is a space-constrained algorithm, therefore we will need a chunk of space to store these values. Think about what a lot of this looks like with respect to how you know how to organize data. | ||
+ | =====Optimizations on sieve of Eratosthenes===== | ||
+ | |||
+ | ====odds-only processing (primesoeodd)==== | ||
+ | Taking the **primesoe** codebase, enhance it to do odds-only processing, ideally considering overall storage used. | ||
+ | |||
+ | ====sqrt() trick (primesoesrt)==== | ||
+ | Taking the **primesoe** codebase, enhance it to utilize the **sqrt()** (or **sqrt()-less square root**) trick. | ||
+ | |||
+ | Compared to the brute/brk algorithms from the previous projects, the performance differences between using **sqrt()** and approximating the square root should be minimal. You are free to utilize either approach in your implementation for this project. | ||
+ | |||
+ | NOTE: this variant is still to process all values (odd and even). | ||
+ | |||
+ | NOTE: if you are curious in comparing actual performance between sqrt() and approximated square root, **primerun** will recognize the following program names: | ||
+ | |||
+ | * **primesoesrt** | ||
+ | * **primesoesrtopt** | ||
+ | |||
+ | ====odds-only+sqrt() trick (primesoesrtodd)==== | ||
+ | Taking the **primesoe** codebase, enhance it to do odds-only processing AND utilize the **sqrt()** (or **sqrt()-less square root**) trick. | ||
+ | |||
+ | Compared to the brute/brk algorithms from the previous projects, the performance differences between using **sqrt()** and approximating the square root should be minimal. You are free to utilize either approach in your implementation for this project. | ||
+ | |||
+ | NOTE: if you are curious in comparing actual performance between sqrt() and approximated square root for this odds-processing variant, **primerun** will recognize the following program names: | ||
+ | |||
+ | * **primesoesrtodd** | ||
+ | * **primesoesrtoptodd** | ||
=====Program===== | =====Program===== | ||
- | It is your task to write some optimized | + | It is your task to write four Sieve of Eratosthenes-oriented |
- | - **primeopt.c**: implementing an approach of your own | + | - **primesoe.c**: using the space-oriented sieve algorithm (baseline sieve) |
- | - **primesieveoferat.c**: using the space-oriented | + | - **primesoeodd.c**: applying |
- | - **primesieveofsund.c**: another | + | - **primesoesrt.c**: applying the sqrt() trick to sieve of Eratosthenes |
+ | - **primesoesrtodd.c**: | ||
- | Your program | + | ====Program Specifications==== |
- | * obtain | + | Your programs |
- | * argv[1]: maximum | + | * obtain |
- | * this value should be a positive integer value; you can make the assumption that the user will always | + | * check to make sure the user indeed supplied enough parameters, and exit with an error message if not. |
- | * do the specified algorithmic optimizations | + | * argv[1]: maximum |
- | * please take note in differences in run-time, contemplating the impact the various algorithms | + | * this value should be an integer value, greater than or equal to 0. |
- | * start your stopwatch (see **timing** section below): | + | * if argv[1] is 0, disable the quantity check, and rely on provided lower and upper bounds |
- | * perform the correct algorithm against the input | + | * argv[2]: reserved for future compatibility; |
- | * display | + | * argv[3]: **conditionally optional** lower bound (starting |
- | * output the processing run-time to STDERR | + | * if omitted, assume a lower bound of **2**. |
- | * your output **MUST** | + | * if you desired to specify an upper bound (argv[4]), you obviously MUST provide the lower bound argument under this scheme. |
+ | * argv[4]: **conditionally optional** upper bound (ending value). If provided, this is the ending | ||
+ | * If doing a quantity run (argv[1] NOT 0), this value isn't necessary. | ||
+ | * If doing a quantity run AND you specify an upper bound, whichever condition is achieved first dictates program termination. That is, upper bound could override quantity (if it is achieved before quantity), and quantity | ||
+ | * for each argument: you should | ||
+ | * for insufficient quantity of arguments, display: **PROGRAM_NAME: | ||
+ | * for invalid argv[1], display: **PROGRAM_NAME: | ||
+ | * for invalid argv[2], display: **PROGRAM_NAME: | ||
+ | * for invalid argv[3], display: **PROGRAM_NAME: | ||
+ | * if argv[3] is not needed, ignore (no error displayed not forced exit, as it is acceptable defined behavior). | ||
+ | * for invalid argv[4], display: **PROGRAM_NAME: | ||
+ | * if argv[4] is not needed, ignore (no error displayed nor forced exit, as it is acceptable defined behavior). | ||
+ | * In these error messages, **PROGRAM_NAME** is the name of the program being run; this can be accessed as a string stored in **argv[0]**. | ||
+ | * please take note in differences in run-time, contemplating the impact the various algorithms/ | ||
+ | * start your stopwatch (see **timing** section below). | ||
+ | * perform the correct algorithm against the input(s) given. | ||
+ | * display to STDOUT | ||
+ | * stop your stopwatch. Calculate | ||
+ | * output the processing run-time to STDERR | ||
+ | * your output **MUST** | ||
* as primes are being displayed, they are space-separated (first prime hugs the left margin), and when all said and done, a newline is issued. | * as primes are being displayed, they are space-separated (first prime hugs the left margin), and when all said and done, a newline is issued. | ||
- | * the timing information will be displayed in accordance to code I will provide (in the **timing** section). | + | * the timing information will be displayed in accordance to code I will provide |
=====Grabit Integration===== | =====Grabit Integration===== | ||
Line 105: | Line 150: | ||
<cli> | <cli> | ||
lab46: | lab46: | ||
- | make: Entering directory '/ | + | make: Entering directory '/ |
- | ‘/ | + | ‘/ |
- | ‘/ | + | ‘/ |
- | ‘/ | + | ‘/ |
- | ‘/ | + | ‘/ |
- | make: Leaving directory '/ | + | ‘/ |
+ | make: Leaving directory '/ | ||
lab46: | lab46: | ||
lab46: | lab46: | ||
- | Makefile | + | Makefile |
lab46: | lab46: | ||
</ | </ | ||
- | Furthermore, | + | Furthermore, |
<cli> | <cli> | ||
lab46: | lab46: | ||
‘./ | ‘./ | ||
- | ‘./primebruteopt.c’ -> ‘../pnc0/primebruteopt.c’ | + | ‘./primebrk.c’ -> ‘../pnc0/primebrk.c’ |
- | ‘./primeodds.c’ -> ‘../pnc1/primeodds.c’ | + | ‘./primebrkodd.c’ -> ‘../pnc1/primebrkodd.c’ |
- | ‘./primesqrt.c’ -> ‘../pnc1/primesqrt.c’ | + | ‘./primebrksrt.c’ -> ‘../pnc1/primebrksrt.c’ |
- | ‘./primesqrtodds.c’ -> ‘../pnc1/primesqrtodds.c’ | + | ‘./primebrkoddsrt.c’ -> ‘../pnc1/primebrkoddsrt.c’ |
- | ‘./primesqrtopt.c’ -> ‘../pnc1/primesqrtopt.c’ | + | ‘./primebrksrtopt.c’ -> ‘../pnc1/primebrksrtopt.c’ |
- | ‘./primesqrtoptodds.c’ -> ‘../pnc1/primesqrtoptodds.c’ | + | ‘./primebrkoddsrtopt.c’ -> ‘../pnc1/primebrkoddsrtopt.c’ |
lab46: | lab46: | ||
</ | </ | ||
Line 139: | Line 185: | ||
Just another "nice thing" we deserve. | Just another "nice thing" we deserve. | ||
- | NOTE: You do NOT want to do this on a populated pnc2 project directory-- it will overwrite files. Only do this on an empty directory. | + | NOTE: You do NOT want to do this on a populated pnc2/ project directory-- it will overwrite files. Only do this on an empty directory. |
=====Command-Line Arguments===== | =====Command-Line Arguments===== | ||
Line 163: | Line 209: | ||
The arguments are accessible via the argv array, in the order they were specified: | The arguments are accessible via the argv array, in the order they were specified: | ||
- | * argv[0]: program invocation (path + program name) | + | |
- | * argv[1]: our maximum / upper bound | + | |
====Simple argument checks==== | ====Simple argument checks==== | ||
Line 189: | Line 235: | ||
And now we can proceed with the rest of our prime implementation. | And now we can proceed with the rest of our prime implementation. | ||
+ | |||
+ | =====Allocating large arrays===== | ||
+ | Being new to arrays, you may not know it yet, but there is an upper bound to how big you can declare an array at **compile time**. | ||
+ | |||
+ | That is, using the conventional array declaration: | ||
+ | |||
+ | <code c> | ||
+ | data_type arrayname[size]; | ||
+ | </ | ||
+ | |||
+ | It is likely dependent on some combination of the execution environment (32-, 64-bit?) and the compiler, but in practice I've found things generally get unhappy if we try to request array sizes at some point beyond 1-4million elements (which makes sense, most processes in modern operating systems allocate a default stack size of 4-8MiB... if a short int is 2 bytes, how many consecutive short ints before you hit 4MiB?) | ||
+ | |||
+ | As we'll be needing array sizes considerably larger than this for the project (will we? If I could drop a hint: **yes, we will**), how do we get around this? | ||
+ | |||
+ | The answer: **runtime memory allocation** | ||
+ | |||
+ | We can allocate memory at run-time, which gives us the benefit of populating variables and performing equations to derive more specific values. This is also a rather powerful programming technique/ | ||
+ | |||
+ | To do so, we ignore the fake facade that is the array, and treat it like it actually exists to the computer: **a pointer**. | ||
+ | |||
+ | So when you declare your array, instead of using the square bracket notation, do it as a pointer instead: | ||
+ | |||
+ | <code c> | ||
+ | datatype *array_name | ||
+ | </ | ||
+ | |||
+ | THEN, later on in your program when it comes time to allocate the array, we use a memory allocation function, of which for our current purposes one of the following 2 could suit our needs: | ||
+ | |||
+ | * **malloc(size)** | ||
+ | * allocates **size** bytes and returns the address | ||
+ | * **calloc(count, | ||
+ | * allocates count * size bytes and returns the address; it also will scrub the memory, making sure everything is set to zero (**malloc()** does not do this; **malloc()** is also faster because of this, something to keep in mind to differentiate the two). | ||
+ | |||
+ | So, if we wanted a 32768 element integer array, to show examples allocating with each function (you'd obviously only use one, whichever best fit your usage scenario): | ||
+ | |||
+ | <code c> | ||
+ | int *array_name | ||
+ | |||
+ | // using malloc() | ||
+ | array_name = (int *) malloc (sizeof(int) * 32768); | ||
+ | |||
+ | // using calloc() | ||
+ | array_name = (int *) calloc (32768, sizeof(int)); | ||
+ | </ | ||
+ | |||
+ | What else is going on here? What's with the parenthesis and the integer pointer? | ||
+ | |||
+ | That's a typecast, and is a way of telling the compiler to contort data IN THAT INSTANCE to a certain type (because it is a different type, other than what we want). | ||
+ | |||
+ | As it turns out, **malloc()** and **calloc()** both return //raw memory//, which in C is manifested as type **< | ||
+ | |||
+ | With this, we can get around the compile time array limits, because by allocating memory at runtime, we're getting additional memory given to us, vs. trying to fit within the default initial allotment. | ||
+ | |||
+ | You should then be able to access it using regular array notation, or my preference: pointer arithmetic. | ||
+ | |||
+ | <code c> | ||
+ | // C array syntax for accessing 3rd element of array: | ||
+ | array_name[2] | ||
+ | |||
+ | // C pointer arithmetic syntax for accessing 3rd element of array: | ||
+ | *(array_name+2) | ||
+ | </ | ||
+ | |||
+ | =====Approximating array size===== | ||
+ | The nature of utilizing an array for the sieves, as you will likely discover quickly, is that the sheer quantity of elements needed increments drastically as the desired quantity goes up. | ||
+ | |||
+ | For example, if we were seeking the first 32 primes: | ||
+ | |||
+ | <cli> | ||
+ | lab46: | ||
+ | 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 | ||
+ | </ | ||
+ | |||
+ | ... we would see that the 32nd prime is 131. For the Sieve of Eratosthenes to successfully work in this case, we'd need an array size of at least 132 (if we do the standard mapping of array element to actual number, where element 0 would correspond with the number 0, and element 131 would correspond with number 131; 0-131 = 132 elements). | ||
+ | |||
+ | But that number isn't immediately known (indeed, the nature of the distribution of prime numbers is the subject of considerable mathematical exploration, | ||
+ | |||
+ | And without this knowledge of the largest prime in the desired quantity, our sieve implementation (with the requirements as I have specified) is sort of at a standstill. | ||
+ | |||
+ | So how do we get around this? I propose a combination of accepting knowledge from a more aware source (me), and a little algebraic ingenuity. Let's hack ourselves an array size equation! (Do I hear a "heck yeah!" ? "HECK YEAH!" | ||
+ | |||
+ | First, you can actually produce a lot of this data, from your **pnc1** programs (technically **pnc0** as well, but you'll be waiting a whole heck of a lot longer). | ||
+ | |||
+ | Let's take one of the purportedly best-running programs from **pnc1** (**primebrksrtoptodd**) and contort it into giving us the information that we need. | ||
+ | |||
+ | With a little bit of UNIX shell magic (again, I'm not expecting you to know this, so I'm just giving it to you, but from the abstract/ | ||
+ | |||
+ | <code bash 1> | ||
+ | # clear the screen | ||
+ | clear | ||
+ | |||
+ | # loop for a powers of 2 progression 32-4194304 (inclusive) | ||
+ | for((qty=32; | ||
+ | |||
+ | # display the quantity lead-in information | ||
+ | printf "[%7s] %7sth prime: " " | ||
+ | | ||
+ | # obtain the last/ | ||
+ | value=$(./ | ||
+ | |||
+ | # display it, along with calculating its approximate multiplier | ||
+ | printf "%8s (x%s)\n" | ||
+ | done | ||
+ | </ | ||
+ | |||
+ | We start with **qty** of 32, as that is the default starting point of **primerun** (so why not; makes sense to work with what we've got). But there' | ||
+ | |||
+ | I'm going to drop a hint: you'll very likely not be going beyond a quantity of **4194304** (at least with a primerun cut-off limit of 2 seconds), so use THAT as your upper bound of quantity, and that is why I use that number in the shell script given above. | ||
+ | |||
+ | You don't have to worry about running said shell script, as the output is right here: | ||
+ | |||
+ | <cli> | ||
+ | [ | ||
+ | [ | ||
+ | [ 128] 128th prime: | ||
+ | [ 256] 256th prime: | ||
+ | [ 512] 512th prime: | ||
+ | [ | ||
+ | [ | ||
+ | [ | ||
+ | [ | ||
+ | [ 16384] | ||
+ | [ 32768] | ||
+ | [ 65536] | ||
+ | [ 131072] | ||
+ | [ 262144] | ||
+ | [ 524288] | ||
+ | [1048576] 1048576th prime: 16290047 (x16) | ||
+ | [2097152] 2097152th prime: 34136029 (x17) | ||
+ | [4194304] 4194304th prime: 71378569 (x18) | ||
+ | </ | ||
+ | |||
+ | What we have is the following: | ||
+ | |||
+ | * first column is the specified quantity we are going to (as instantiated by primerun; I just have us doing a simple powers of 2 progression) | ||
+ | * the next column (the N-th prime), is the last prime in that quantity sequence (131 IS the 32nd prime, starting from 2) | ||
+ | * the last column, the xNUMBER, is the approximate multiplier we get by dividing the N-th prime by the quantity (and taking the ceiling (I just added one, since we're doing integer division and it'll truncate anyway), since it likely will NOT be a clean division) | ||
+ | |||
+ | So from the data given above, we can see that a rough approximation of space needed for 32 primes would be < | ||
+ | |||
+ | For 1024 we have a multiplier of 8 (< | ||
+ | |||
+ | Okay, so we've got some raw numbers, we know the array size needed for the smallest quantity (< | ||
+ | |||
+ | As you can see, there is no a clean progression at play here, so no simple patterns we can play off of. I offer a few suggestions (and for the purposes of this project, any are acceptable): | ||
+ | |||
+ | * just go with the max size (x18): **< | ||
+ | * deploy some **if()** statements and do a stepped progression. | ||
+ | |||
+ | For example, we see that since our max multiplier is 18, what if we did some factoring of 18? Say: 6, 12, 18? | ||
+ | |||
+ | We could rig up something like this: | ||
+ | |||
+ | <code c> | ||
+ | if (qty <= 128) | ||
+ | array_size = qty * 6; | ||
+ | else if (qty <= 32768) | ||
+ | array_size = qty * 12; | ||
+ | else | ||
+ | array_size = qty * 18; | ||
+ | </ | ||
+ | |||
+ | In general, though, this is just a mild annoyance in our quest to implement the sieve of Eratosthenes, | ||
+ | |||
+ | Make sense? Hopefully. And moreso, if you've been able to follow this, it is also indicative of your general level of comprehension: | ||
+ | |||
+ | And please, ASK QUESTIONS if something doesn' | ||
=====Timing===== | =====Timing===== | ||
Line 248: | Line 461: | ||
<cli> | <cli> | ||
- | lab46: | + | lab46: |
- | 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 | + | 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 |
0.000088 | 0.000088 | ||
lab46: | lab46: | ||
Line 256: | Line 469: | ||
The execution of the programs is short and simple- grab the parameters, do the processing, produce the output, and then terminate. | The execution of the programs is short and simple- grab the parameters, do the processing, produce the output, and then terminate. | ||
- | ====Performance changes==== | + | Based on specifications, |
- | You may notice a change with the sieves as compared | + | |
- | =====Check Results===== | + | <cli> |
- | If you'd like to compare your implementations, | + | lab46: |
+ | 5 7 11 13 17 | ||
+ | 0.000080 | ||
+ | lab46: | ||
+ | </ | ||
- | In order to work, you **MUST** be in the directory where your previous prime programs are. What I do is symlink the sources or copy the binaries into my current directory (pnc2), so I both have access to everything, but everything is still categorized per project. | + | And (shift |
- | + | ||
- | I'm not yet posting my primerun results; if you implement these correctly the results should speak for themselves. | + | |
<cli> | <cli> | ||
- | lab46: | + | lab46: |
- | COMING SOON | + | 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 |
+ | 0.000087 | ||
lab46: | lab46: | ||
</ | </ | ||
- | For evaluation, each test is run 4 times, and the resulting time is averaged. During development, I have it set to only run each test once. | + | And of course the same for the 3 variants, and the same error message reporting if invalid values are given. |
+ | ====Performance changes==== | ||
+ | You may notice a change with the sieves as compared to the other algorithms you've implemented with respect to performance- there will likely be a lower bound of performance, ie you have to exceed a certain threshold before the algorithm truly enters its power band, and then it may truly be a step-up in terms of performance. | ||
+ | |||
+ | =====Check Results===== | ||
+ | To verify your program' | ||
+ | |||
+ | I'll hold off from posting actual primerun output; I want you to see the results without any expectations. Do know that the arrangement of programs (from left to right) is in order of worst to best performance based on my implementations. | ||
- | If the runtime of a particular prime variant exceeds an upper threshold (likely to be set at 2 seconds), it will be omitted from further tests, and a series of dashes will instead appear in the output. | + | If/when the runtime of a particular prime variant exceeds an upper threshold (likely to be set at 2 seconds), it will be omitted from further tests, and a series of dashes will instead appear in the output. |
If you don't feel like waiting, simply hit **CTRL-c** and the script will terminate. | If you don't feel like waiting, simply hit **CTRL-c** and the script will terminate. | ||
Line 286: | Line 508: | ||
* Output must be correct, and match the form given in the sample output above. | * Output must be correct, and match the form given in the sample output above. | ||
* Code must be nicely and consistently indented (you may use the **indent** tool) | * Code must be nicely and consistently indented (you may use the **indent** tool) | ||
- | * Code must utilize the specifications/ | + | * Code must utilize the algorithm(s) presented above. |
- | * **primeopt.c** | + | * **primesoe.c** |
- | * **primesieveoferat.c** | + | * **primesoeodd.c** |
- | * **primesieveofsund.c** | + | * **primesoesrt.c** |
+ | * **primesoesrtodd.c** | ||
* Code must be commented | * Code must be commented | ||
* have a properly filled-out comment banner at the top | * have a properly filled-out comment banner at the top | ||
Line 301: | Line 524: | ||
<cli> | <cli> | ||
- | $ submit cprog pnc2 primeopt.c primesieveoferat.c primesieveofsund | + | $ submit cprog pnc2 primesoe.c primesoeodd.c primesoesrt.c primesoesrtodd.c |
Submitting cprog project " | Submitting cprog project " | ||
- | -> primeopt.c(OK) | + | -> primesoe.c(OK) |
- | -> primesieveoferat.c(OK) | + | -> primesoeodd.c(OK) |
- | -> primesieveofsund.c(OK) | + | -> primesoesrt.c(OK) |
+ | -> primesoesrtodd.c(OK) | ||
SUCCESSFULLY SUBMITTED | SUCCESSFULLY SUBMITTED | ||
Line 315: | Line 539: | ||
< | < | ||
- | 52:pnc2:final tally of results (52/0) | + | 78:pnc2:final tally of results (78/0) |
- | *: | + | *: |
- | *:pnc2:primeopt.c no negative compiler messages [2/0] | + | *:pnc2:primesoe.c no negative compiler messages [2/2] |
- | *:pnc2:primeopt.c implements | + | *:pnc2:primesoe.c implements |
- | *:pnc2:primeopt.c adequate indentation and comments [3/0] | + | *:pnc2:primesoe.c adequate indentation and comments [3/3] |
- | *:pnc2:primeopt.c output conforms to specifications [4/0] | + | *:pnc2:primesoe.c output conforms to specifications [3/3] |
- | *:pnc2:primeopt.c primerun runtime tests succeed [4/0] | + | *:pnc2:primesoe.c primerun runtime tests succeed [3/3] |
- | *:pnc2:primesieveoferat.c no negative compiler messages [2/0] | + | *:pnc2:primesoeodd.c no negative compiler messages [2/2] |
- | *:pnc2:primesieveoferat.c implements only specified algorithm [4/0] | + | *:pnc2:primesoeodd.c implements only specified algorithm [8/8] |
- | *:pnc2:primesieveoferat.c adequate indentation and comments [3/0] | + | *:pnc2:primesoeodd.c adequate indentation and comments [3/3] |
- | *:pnc2:primesieveoferat.c output conforms to specifications [4/0] | + | *:pnc2:primesoeodd.c output conforms to specifications [3/3] |
- | *:pnc2:primesieveoferat.c primerun runtime tests succeed [4/0] | + | *:pnc2:primesoeodd.c primerun runtime tests succeed [3/3] |
- | *:pnc2:primesieveofsund.c no negative compiler messages [2/0] | + | *:pnc2:primesoesrt.c no negative compiler messages [2/2] |
- | *:pnc2:primesieveofsund.c implements only specified algorithm [4/0] | + | *:pnc2:primesoesrt.c implements only specified algorithm [8/8] |
- | *:pnc2:primesieveofsund.c adequate indentation and comments [3/0] | + | *:pnc2:primesoesrt.c adequate indentation and comments [3/3] |
- | *:pnc2:primesieveofsund.c output conforms to specifications [4/0] | + | *:pnc2:primesoesrt.c output conforms to specifications [3/3] |
- | *:pnc2:primesieveofsund.c primerun runtime tests succeed [4/0] | + | *:pnc2:primesoesrt.c primerun runtime tests succeed [3/3] |
+ | *: | ||
+ | *: | ||
+ | *: | ||
+ | *: | ||
+ | *: | ||
</ | </ |