#include #include #include /** INSTRUCTIONS FOR ALL TASKS ** ** Rewrite every function so that they no longer use ANY of the following ** constructs: { setjmp, longjmp, goto, continue, break } and each function ** may have only *one* use of the return form, at the end of the function ** definition, e.g.: ** ** int abs(int x) { ** z = x; ** if (x < 0) ** z = -x; ** return z; ** } ** **/ /* Task 1: return */ /* usage: roots( a, b, c ) returns number of roots of * quadratic equation ax^2 + bx + c. */ int roots( int a, int b, int c ) { int discrim = (b*b - 4*a*c); if (discrim > 0) { return 2; } else if (discrim == 0) { return 1; } else { return 0; } } /* Task 2: break */ /* requires: array has length k * usage: prod( A, k ) returns the product A[0] * A[1] * ... * A[k-1]. */ int prod( int *array, int k ) { int index = 0; int product = 1; while ( index < k ) { if (array[index] == 0) { product = 0; break; } else { product = product * array[index]; index = index + 1; } } return product; } /* Task 3: break (again) */ /* requires: array has length k * usage: find( A, k, j ) returns the index of the first occurrence * of j in A. If j does not occur in A, then returns k. */ int find( int *array, int k, int j ) { int index = 0; while ( index < k ) { if (array[index] == j) { break; } index = index + 1; } return index; } /* Task 4: continue */ /* requires: array has length k * usage: mystery(A, k) returns a mysterious sum of some elements in A. */ int mystery( int *array, int k ) { int i, j; int sum = 0; i = 0; while ( i < k ) { j = i; i = i + 1; while ( j < k ) { j = j + 1; if (array[j-1] == 1) { continue; } sum = sum + array[j-1]; } } return sum; } /* Task 5: goto */ /* requires: a or b is non-zero. * usage: gcd(a,b) returns the greatest common divisor of a and b */ int gcd( int a, int b ) { int t; restart: if (b != 0) { t = b; b = a % b; a = t; goto restart; } return a; } /* Task 6: setjmp/longjmp */ /* Let P = k * k-1 * k-2 * ... * 1. * If P fits in a C integer, returns P. Else returns k. */ int fact_like( int k ) { jmp_buf env; /* setjmp saves its continuation, Kappa, in env, and then returns 0 * to Kappa. So if setjmp returns 0 to Kappa, why the if statement * here? See longjmp below. */ if (0 == setjmp(env)) { return fact_core( k, env ); } else { return k; } } /* Helper for fact_like. Computes factorial, but escapes through * continuation stored in env if we encounter overflow. */ int fact_core( int k, jmp_buf env ) { if (k == 1) { return 1; } else { int factprev = fact_core( k-1, env ); int retval = k * factprev; int orig = retval / k; /* How could orig != factprev? */ if ( orig != factprev ) { /* longjmp( env, X ) abandons its continuation and returns X * through the continuation Kappa saved in env. */ longjmp( env, 1 ); } else { return retval; } } } /** ** ** START OF TESTING CODE (both test procedures and example input data). ** ** **/ int four_twos[] = { 2, 2, 2, 2 }; int nine_to_zero[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; int ten_to_one[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; int ten_to_one_twice[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; int four_twoones[] = { 2, 1, 2, 1, 2, 1, 2, 1 }; int test( int task_num, char* test_name, int actual, int expected ) { int test_failure; if (actual == expected) { printf( "test success task %d \"%s\"\n", task_num, test_name ); test_failure = 0; } else { printf( "TEST FAILURE TASK %d \"%s\" expected: %d actual: %d\n", task_num, test_name, expected, actual ); test_failure = 1; } return test_failure; } /* usage: returns number of test failures for Task 1. */ int test_task1() { int c = 0; c = c + test( 1, "roots 4x^2", roots( 4, 0, 0 ), 1 ); c = c + test( 1, "roots 4x^2 + 1", roots( 4, 0, 1 ), 0 ); c = c + test( 1, "roots x^2 - 4x", roots( 1,-4, 0 ), 2 ); c = c + test( 1, "roots x^2 + 4", roots( 1, 0, 4 ), 0 ); c = c + test( 1, "roots x^2 + 2x + 1", roots( 1, 2, 1 ), 1 ); c = c + test( 1, "roots 2x^2 + 6x + 4", roots( 2, 6, 4 ), 2 ); c = c + test( 1, "roots 2x^2 + 6x + 5", roots( 2, 6, 5 ), 0 ); return c; } /* usage: returns number of test failures for Task 2. */ int test_task2() { int c = 0; c = c + test( 2, "prod [2,2,2,2]", prod( four_twos, 4 ), 16 ); c = c + test( 2, "prod [9,8,...,0])", prod( nine_to_zero, 10 ), 0 ); c = c + test( 2, "prod [10,9,...,1])", prod( ten_to_one, 10 ), 3628800 ); return c; } /* usage: returns number of test failures for Task 3. */ int test_task3() { int c = 0; c = c + test( 3, "find 2 in [2,2,2,2]", find( four_twos, 4, 2 ), 0 ); c = c + test( 3, "find 8 in [9,8,...,0]", find( nine_to_zero, 10, 8 ), 1 ); c = c + test( 3, "find 7 in [9,8,...,0]", find( nine_to_zero, 10, 7 ), 2 ); c = c + test( 3, "find 7 in [9,8,...,0]", find( nine_to_zero, 10, 7 ), 2 ); c = c + test( 3, "find 1 in [10,9,...,1]", find( ten_to_one, 10, 1 ), 9 ); c = c + test( 3, "find 1 in [10,9,...,1,10,9,...,1]", find( ten_to_one_twice, 10, 1 ), 9 ); c = c + test( 3, "find 0 in [10,9,...,1]", find( ten_to_one, 10, 0 ), 10); return c; } /* usage: returns number of test failures for Task 4. */ int test_task4() { int c = 0; c += test( 4, "mystery [2,2,2,2]", mystery( four_twos, 4 ), 20); c += test( 4, "mystery [2,1,2,1,2,1,2,1]", mystery( four_twoones, 8 ), 32); return c; } /* usage: returns number of test failures for Task 5. */ int test_task5() { int c = 0; c = c + test( 5, "gcd(42,56)", gcd( 42, 56 ), 14); c = c + test( 5, "gcd(1071,1029)", gcd( 1071, 1029 ), 21); return c; } /* usage: returns number of test failures for Task 6. */ int test_task6() { int c = 0; c = c + test( 6, "10!", fact_like( 10 ), 3628800); c = c + test( 6, "12!", fact_like( 12 ), 479001600); c = c + test( 6, "fact_like(1000)", fact_like( 1000 ), 1000); return c; } /* usage: runs test suite for MP7; returns number of test failures. * Optional argument indicates individual task to test. */ int main( int argc, char** argv ) { int failure_count = 0; if (argc == 1) { failure_count = failure_count + test_task1(); failure_count = failure_count + test_task2(); failure_count = failure_count + test_task3(); failure_count = failure_count + test_task4(); failure_count = failure_count + test_task5(); failure_count = failure_count + test_task6(); } else { if (0 == strcmp(argv[1],"1")) { failure_count = failure_count + test_task1(); } else if (0 == strcmp(argv[1],"2")) { failure_count = failure_count + test_task2(); } else if (0 == strcmp(argv[1],"3")) { failure_count = failure_count + test_task3(); } else if (0 == strcmp(argv[1],"4")) { failure_count = failure_count + test_task4(); } else if (0 == strcmp(argv[1],"5")) { failure_count = failure_count + test_task5(); } else if (0 == strcmp(argv[1],"6")) { failure_count = failure_count + test_task6(); } else { printf("warning: argument was \"%s\", expected 1 2 3 4 5 or 6.\n"); } } printf("Testing complete; %d test failures.\n", failure_count); if (failure_count != 0) { return 1; } else { return 0; } }