diff --git a/.github/workflows/classroom.yml b/.github/workflows/classroom.yml index 544c055..ed7dd21 100644 --- a/.github/workflows/classroom.yml +++ b/.github/workflows/classroom.yml @@ -260,6 +260,19 @@ jobs: comparison-method: contains timeout: 10 max-score: 2 + - name: bitReverse + id: bitreverse + uses: classroom-resources/autograding-io-grader@v1 + with: + test-name: bitReverse + setup-command: sudo apt-get install gcc-multilib && make clean + && make all + command: ./btest -f bitReverse + input: '' + expected-output: 'Total points: 2/2' + comparison-method: contains + timeout: 10 + max-score: 2 - name: Autograding Reporter uses: classroom-resources/autograding-grading-reporter@v1 env: @@ -282,5 +295,6 @@ jobs: FLOAT_I2F_RESULTS: "${{steps.float_i2f.outputs.result}}" ODDPARITY_RESULTS: "${{steps.oddparity.outputs.result}}" BITCOUNT_RESULTS: "${{steps.bitcount.outputs.result}}" + BITREVERSE_RESULTS: "${{steps.bitreverse.outputs.result}}" with: - runners: operator-check,signmask,bitxor,clearbyte,roundup,negativepart,islargerorequal,logicalshift,swapnibblepairs,secondlowestzerobit,rotaterightbits,fractions,overflowcalc,mul5sat,float_inv,float_half,float_i2f,oddparity,bitcount \ No newline at end of file + runners: operator-check,signmask,bitxor,clearbyte,roundup,negativepart,islargerorequal,logicalshift,swapnibblepairs,secondlowestzerobit,rotaterightbits,fractions,overflowcalc,mul5sat,float_inv,float_half,float_i2f,oddparity,bitcount,bitreverse \ No newline at end of file diff --git a/bits.c b/bits.c index 5dd4a52..74d5e0d 100644 --- a/bits.c +++ b/bits.c @@ -631,3 +631,27 @@ int bitCount(int x) { return x; } + +// P19 +/* + * bitReverse - Reverse bits in an 32-bit integer + * Examples: bitReverse(0x80000004) = 0x20000001 + * bitReverse(0x7FFFFFFF) = 0xFFFFFFFE + * Legal ops: ! ~ & ^ | + << >> + * Max ops: 56 + * Rating: 2 + */ +int bitReverse(int x) +{ + int m1 = 255 + (255 << 8); + int m2 = m1 ^ (m1 << 8); + int m3 = m2 ^ (m2 << 4); + int m4 = m3 ^ (m3 << 2); + int m5 = m4 ^ (m4 << 1); + x = ((x >> 16) & m1) + (x << 16); + x = ((x & m2) << 8) + ((x >> 8) & m2); + x = ((x & m3) << 4) + ((x >> 4) & m3); + x = ((x & m4) << 2) + ((x >> 2) & m4); + x = ((x & m5) << 1) + ((x >> 1) & m5); + return x; +} diff --git a/bits.h b/bits.h index 38703d9..f5392ca 100644 --- a/bits.h +++ b/bits.h @@ -14,6 +14,7 @@ int bitXor(int x, int y); int negativePart(int x); int isLargerOrEqual(int x, int y); int bitCount(int x); +int bitReverse(int x); int logicalShift(int x, int n); unsigned float_half(unsigned uf); @@ -34,6 +35,7 @@ int test_signMask(void); int test_negativePart(int x); int test_isLargerOrEqual(int x, int y); int test_bitCount(int x); +int test_bitReverse(int x); int test_logicalShift(int x, int n); unsigned test_float_half(unsigned uf); int test_mul5Sat(int x); diff --git a/btest.c b/btest.c index 3d45570..22c0c7c 100644 --- a/btest.c +++ b/btest.c @@ -1,6 +1,6 @@ -/* - * CS:APP Data Lab - * +/* + * CS:APP Data Lab + * * btest.c - A test harness that checks a student's solution in bits.c * for correctness. * @@ -10,7 +10,7 @@ * This is an improved version of btest that tests large windows * around zero and tmin and tmax for integer puzzles, and zero, norm, * and denorm boundaries for floating point puzzles. - * + * * Note: not 64-bit safe. Always compile with gcc -m32 option. */ #include @@ -44,20 +44,20 @@ float strtof(const char *nptr, char **endptr); /* This defines the maximum size of any test value array. The gen_vals() routine creates k test values for each value of TEST_RANGE, thus MAX_TEST_VALS must be at least k*TEST_RANGE */ -#define MAX_TEST_VALS 13*TEST_RANGE +#define MAX_TEST_VALS 13 * TEST_RANGE /********************************** - * Globals defined in other modules + * Globals defined in other modules **********************************/ /* This characterizes the set of puzzles to test. Defined in decl.c and generated from templates in ./puzzles dir */ -extern test_rec test_set[]; +extern test_rec test_set[]; /************************************************ * Write-once globals defined by command line args ************************************************/ -/* Emit results in a format for autograding, without showing +/* Emit results in a format for autograding, without showing and counter-examples */ static int grade = 0; @@ -65,11 +65,11 @@ static int grade = 0; static int timeout_limit = TIMEOUT_LIMIT; /* -T */ /* If non-NULL, test only one function (-f) */ -static char* test_fname = NULL; +static char *test_fname = NULL; /* Special case when only use fixed argument(s) (-1, -2, or -3) */ -static int has_arg[3] = {0,0,0}; -static unsigned argval[3] = {0,0,0}; +static int has_arg[3] = {0, 0, 0}; +static unsigned argval[3] = {0, 0, 0}; /* Use fixed weight for rating, and if so, what should it be? (-r) */ static int global_rating = 0; @@ -83,501 +83,532 @@ static int global_rating = 0; */ typedef void handler_t(int); -handler_t *Signal(int signum, handler_t *handler) +handler_t *Signal(int signum, handler_t *handler) { - struct sigaction action, old_action; + struct sigaction action, old_action; - action.sa_handler = handler; - sigemptyset(&action.sa_mask); /* block sigs of type being handled */ - action.sa_flags = SA_RESTART; /* restart syscalls if possible */ + action.sa_handler = handler; + sigemptyset(&action.sa_mask); /* block sigs of type being handled */ + action.sa_flags = SA_RESTART; /* restart syscalls if possible */ - if (sigaction(signum, &action, &old_action) < 0) - perror("Signal error"); - return (old_action.sa_handler); + if (sigaction(signum, &action, &old_action) < 0) + perror("Signal error"); + return (old_action.sa_handler); } -/* - * timeout_handler - SIGALARM hander +/* + * timeout_handler - SIGALARM hander */ sigjmp_buf envbuf; -void timeout_handler(int sig) { - siglongjmp(envbuf, 1); +void timeout_handler(int sig) +{ + siglongjmp(envbuf, 1); } -/* - * random_val - Return random integer value between min and max +/* + * random_val - Return random integer value between min and max */ static int random_val(int min, int max) { - double weight = rand()/(double) RAND_MAX; - int result = min * (1-weight) + max * weight; - return result; + double weight = rand() / (double)RAND_MAX; + int result = min * (1 - weight) + max * weight; + return result; } -/* - * gen_vals - Generate the integer values we'll use to test a function +/* + * gen_vals - Generate the integer values we'll use to test a function */ static int gen_vals(int test_vals[], int min, int max, int test_range, int arg) { - int i; - int test_count = 0; - - /* Special case: If the user has specified a specific function - argument using the -1, -2, or -3 flags, then simply use this - argument and return */ - if (has_arg[arg]) { - test_vals[0] = argval[arg]; - return 1; - } - - /* - * Special case: Generate test vals for floating point functions - * where the input argument is an unsigned bit-level - * representation of a float. For this case we want to test the - * regions around zero, the smallest normalized and largest - * denormalized numbers, one, and the largest normalized number, - * as well as inf and nan. - */ - if ((min == 1 && max == 1)) { - unsigned smallest_norm = 0x00800000; - unsigned one = 0x3f800000; - unsigned largest_norm = 0x7f000000; - - unsigned inf = 0x7f800000; - unsigned nan = 0x7fc00000; - unsigned sign = 0x80000000; - - /* Test range should be at most 1/2 the range of one exponent - value */ - if (test_range > (1 << 23)) { - test_range = 1 << 23; - } - - /* Functions where the input argument is an unsigned bit-level - representation of a float. The number of tests generated - inside this loop body is the value k referenced in the - comment for the global variable MAX_TEST_VALS. */ - - for (i = 0; i < test_range; i++) { - /* Denorms around zero */ - test_vals[test_count++] = i; - test_vals[test_count++] = sign | i; - - /* Region around norm to denorm transition */ - test_vals[test_count++] = smallest_norm + i; - test_vals[test_count++] = smallest_norm - i; - test_vals[test_count++] = sign | (smallest_norm + i); - test_vals[test_count++] = sign | (smallest_norm - i); - - /* Region around one */ - test_vals[test_count++] = one + i; - test_vals[test_count++] = one - i; - test_vals[test_count++] = sign | (one + i); - test_vals[test_count++] = sign | (one - i); - - /* Region below largest norm */ - test_vals[test_count++] = largest_norm - i; - test_vals[test_count++] = sign | (largest_norm - i); + int i; + int test_count = 0; + + /* Special case: If the user has specified a specific function + argument using the -1, -2, or -3 flags, then simply use this + argument and return */ + if (has_arg[arg]) + { + test_vals[0] = argval[arg]; + return 1; } - - /* special vals */ - test_vals[test_count++] = inf; /* inf */ - test_vals[test_count++] = sign | inf; /* -inf */ - test_vals[test_count++] = nan; /* nan */ - test_vals[test_count++] = sign | nan; /* -nan */ - return test_count; - } + /* + * Special case: Generate test vals for floating point functions + * where the input argument is an unsigned bit-level + * representation of a float. For this case we want to test the + * regions around zero, the smallest normalized and largest + * denormalized numbers, one, and the largest normalized number, + * as well as inf and nan. + */ + if ((min == 1 && max == 1)) + { + unsigned smallest_norm = 0x00800000; + unsigned one = 0x3f800000; + unsigned largest_norm = 0x7f000000; + + unsigned inf = 0x7f800000; + unsigned nan = 0x7fc00000; + unsigned sign = 0x80000000; + + /* Test range should be at most 1/2 the range of one exponent + value */ + if (test_range > (1 << 23)) + { + test_range = 1 << 23; + } + /* Functions where the input argument is an unsigned bit-level + representation of a float. The number of tests generated + inside this loop body is the value k referenced in the + comment for the global variable MAX_TEST_VALS. */ + + for (i = 0; i < test_range; i++) + { + /* Denorms around zero */ + test_vals[test_count++] = i; + test_vals[test_count++] = sign | i; + + /* Region around norm to denorm transition */ + test_vals[test_count++] = smallest_norm + i; + test_vals[test_count++] = smallest_norm - i; + test_vals[test_count++] = sign | (smallest_norm + i); + test_vals[test_count++] = sign | (smallest_norm - i); + + /* Region around one */ + test_vals[test_count++] = one + i; + test_vals[test_count++] = one - i; + test_vals[test_count++] = sign | (one + i); + test_vals[test_count++] = sign | (one - i); + + /* Region below largest norm */ + test_vals[test_count++] = largest_norm - i; + test_vals[test_count++] = sign | (largest_norm - i); + } - /* - * Normal case: Generate test vals for integer functions - */ + /* special vals */ + test_vals[test_count++] = inf; /* inf */ + test_vals[test_count++] = sign | inf; /* -inf */ + test_vals[test_count++] = nan; /* nan */ + test_vals[test_count++] = sign | nan; /* -nan */ - /* If the range is small enough, then do exhaustively */ - if (max - MAX_TEST_VALS <= min) { - for (i = min; i <= max; i++) - test_vals[test_count++] = i; - return test_count; - } + return test_count; + } + + /* + * Normal case: Generate test vals for integer functions + */ - /* Otherwise, need to sample. Do so near the boundaries, around - zero, and for some random cases. */ - for (i = 0; i < test_range; i++) { + /* If the range is small enough, then do exhaustively */ + if (max - MAX_TEST_VALS <= min) + { + for (i = min; i <= max; i++) + test_vals[test_count++] = i; + return test_count; + } - /* Test around the boundaries */ - test_vals[test_count++] = min + i; - test_vals[test_count++] = max - i; + /* Otherwise, need to sample. Do so near the boundaries, around + zero, and for some random cases. */ + for (i = 0; i < test_range; i++) + { - /* If zero falls between min and max, then also test around zero */ - if (i >= min && i <= max) - test_vals[test_count++] = i; - if (-i >= min && -i <= max) - test_vals[test_count++] = -i; + /* Test around the boundaries */ + test_vals[test_count++] = min + i; + test_vals[test_count++] = max - i; - /* Random case between min and max */ - test_vals[test_count++] = random_val(min, max); + /* If zero falls between min and max, then also test around zero */ + if (i >= min && i <= max) + test_vals[test_count++] = i; + if (-i >= min && -i <= max) + test_vals[test_count++] = -i; - } - return test_count; + /* Random case between min and max */ + test_vals[test_count++] = random_val(min, max); + } + return test_count; } -/* - * test_0_arg - Test a function with zero arguments +/* + * test_0_arg - Test a function with zero arguments */ static int test_0_arg(funct_t f, funct_t ft, char *name) { - int r = f(); - int rt = ft(); - int error = (r != rt); + int r = f(); + int rt = ft(); + int error = (r != rt); - if (error && !grade) - printf("ERROR: Test %s() failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, r, r, rt, rt); + if (error && !grade) + printf("ERROR: Test %s() failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, r, r, rt, rt); - return error; + return error; } -/* - * test_1_arg - Test a function with one argument +/* + * test_1_arg - Test a function with one argument */ static int test_1_arg(funct_t f, funct_t ft, int arg1, char *name) { - funct1_t f1 = (funct1_t) f; - funct1_t f1t = (funct1_t) ft; - int r, rt, error; + funct1_t f1 = (funct1_t)f; + funct1_t f1t = (funct1_t)ft; + int r, rt, error; - r = f1(arg1); - rt = f1t(arg1); - error = (r != rt); - if (error && !grade) - printf("ERROR: Test %s(%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, r, r, rt, rt); + r = f1(arg1); + rt = f1t(arg1); + error = (r != rt); + if (error && !grade) + printf("ERROR: Test %s(%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, r, r, rt, rt); - return error; + return error; } -/* - * test_2_arg - Test a function with two arguments +/* + * test_2_arg - Test a function with two arguments */ static int test_2_arg(funct_t f, funct_t ft, int arg1, int arg2, char *name) { - funct2_t f2 = (funct2_t) f; - funct2_t f2t = (funct2_t) ft; - int r = f2(arg1, arg2); - int rt = f2t(arg1, arg2); - int error = (r != rt); + funct2_t f2 = (funct2_t)f; + funct2_t f2t = (funct2_t)ft; + int r = f2(arg1, arg2); + int rt = f2t(arg1, arg2); + int error = (r != rt); - if (error && !grade) - printf("ERROR: Test %s(%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, r, r, rt, rt); + if (error && !grade) + printf("ERROR: Test %s(%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, r, r, rt, rt); - return error; + return error; } -/* - * test_3_arg - Test a function with three arguments +/* + * test_3_arg - Test a function with three arguments */ -static int test_3_arg(funct_t f, funct_t ft, - int arg1, int arg2, int arg3, char *name) +static int test_3_arg(funct_t f, funct_t ft, + int arg1, int arg2, int arg3, char *name) { - funct3_t f3 = (funct3_t) f; - funct3_t f3t = (funct3_t) ft; - int r = f3(arg1, arg2, arg3); - int rt = f3t(arg1, arg2, arg3); - int error = (r != rt); + funct3_t f3 = (funct3_t)f; + funct3_t f3t = (funct3_t)ft; + int r = f3(arg1, arg2, arg3); + int rt = f3t(arg1, arg2, arg3); + int error = (r != rt); - if (error && !grade) - printf("ERROR: Test %s(%d[0x%x],%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, arg3, arg3, r, r, rt, rt); + if (error && !grade) + printf("ERROR: Test %s(%d[0x%x],%d[0x%x],%d[0x%x]) failed...\n...Gives %d[0x%x]. Should be %d[0x%x]\n", name, arg1, arg1, arg2, arg2, arg3, arg3, r, r, rt, rt); - return error; + return error; } -/* - * test_function - Test a function. Return number of errors +/* + * test_function - Test a function. Return number of errors */ -static int test_function(test_ptr t) { - int test_counts[3]; /* number of test values for each arg */ - int args = t->args; /* number of function arguments */ - int arg_test_range[3] = {0, 0, 0}; /* test range for each argument */ - int i, a1, a2, a3; - int errors = 0; - - /* These are the test values for each arg. Declared with the - static attribute so that the array will be allocated in bss - rather than the stack */ - static int arg_test_vals[3][MAX_TEST_VALS]; - - /* Sanity check on the number of args */ - if (args < 0 || args > 3) { - printf("Configuration error: invalid number of args (%d) for function %s\n", args, t->name); - exit(1); - } - - /* Assign range of argument test vals so as to conserve the total - number of tests, independent of the number of arguments */ - if (args == 1) { - arg_test_range[0] = TEST_RANGE; - } - else if (args == 2) { - arg_test_range[0] = pow((double)TEST_RANGE, 0.5); /* sqrt */ - arg_test_range[1] = arg_test_range[0]; - } - else { - arg_test_range[0] = pow((double)TEST_RANGE, 0.333); /* cbrt */ - arg_test_range[1] = arg_test_range[0]; - arg_test_range[2] = arg_test_range[0]; - } - - /* Sanity check on the ranges */ - if (arg_test_range[0] < 1) - arg_test_range[0] = 1; - if (arg_test_range[1] < 1) - arg_test_range[1] = 1; - if (arg_test_range[2] < 1) - arg_test_range[2] = 1; - - /* Create a test set for each argument */ - for (i = 0; i < args; i++) { - test_counts[i] = gen_vals(arg_test_vals[i], - t->arg_ranges[i][0], /* min */ - t->arg_ranges[i][1], /* max */ - arg_test_range[i], - i); - - } - - /* Handle timeouts in the test code */ - if (timeout_limit > 0) { - int rc; - rc = sigsetjmp(envbuf, 1); - if (rc) { - /* control will reach here if there is a timeout */ - errors = 1; - printf("ERROR: Test %s failed.\n Timed out after %d secs (probably infinite loop)\n", t->name, timeout_limit); - return errors; +static int test_function(test_ptr t) +{ + int test_counts[3]; /* number of test values for each arg */ + int args = t->args; /* number of function arguments */ + int arg_test_range[3] = {0, 0, 0}; /* test range for each argument */ + int i, a1, a2, a3; + int errors = 0; + + /* These are the test values for each arg. Declared with the + static attribute so that the array will be allocated in bss + rather than the stack */ + static int arg_test_vals[3][MAX_TEST_VALS]; + + /* Sanity check on the number of args */ + if (args < 0 || args > 3) + { + printf("Configuration error: invalid number of args (%d) for function %s\n", args, t->name); + exit(1); } - alarm(timeout_limit); - } + /* Assign range of argument test vals so as to conserve the total + number of tests, independent of the number of arguments */ + if (args == 1) + { + arg_test_range[0] = TEST_RANGE; + } + else if (args == 2) + { + arg_test_range[0] = pow((double)TEST_RANGE, 0.5); /* sqrt */ + arg_test_range[1] = arg_test_range[0]; + } + else + { + arg_test_range[0] = pow((double)TEST_RANGE, 0.333); /* cbrt */ + arg_test_range[1] = arg_test_range[0]; + arg_test_range[2] = arg_test_range[0]; + } - /* Test function has no arguments */ - if (args == 0) { - errors += test_0_arg(t->solution_funct, t->test_funct, t->name); - return errors; - } - - /* - * Test function has at least one argument - */ - - /* Iterate over the values for first argument */ - - for (a1 = 0; a1 < test_counts[0]; a1++) { - if (args == 1) { - errors += test_1_arg(t->solution_funct, - t->test_funct, - arg_test_vals[0][a1], - t->name); - - /* Stop testing if there is an error */ - if (errors) - return errors; - } - else { - /* if necessary, iterate over values for second argument */ - for (a2 = 0; a2 < test_counts[1]; a2++) { - if (args == 2) { - errors += test_2_arg(t->solution_funct, - t->test_funct, - arg_test_vals[0][a1], - arg_test_vals[1][a2], - t->name); - - /* Stop testing if there is an error */ - if (errors) + /* Sanity check on the ranges */ + if (arg_test_range[0] < 1) + arg_test_range[0] = 1; + if (arg_test_range[1] < 1) + arg_test_range[1] = 1; + if (arg_test_range[2] < 1) + arg_test_range[2] = 1; + + /* Create a test set for each argument */ + for (i = 0; i < args; i++) + { + test_counts[i] = gen_vals(arg_test_vals[i], + t->arg_ranges[i][0], /* min */ + t->arg_ranges[i][1], /* max */ + arg_test_range[i], + i); + } + + /* Handle timeouts in the test code */ + if (timeout_limit > 0) + { + int rc; + rc = sigsetjmp(envbuf, 1); + if (rc) + { + /* control will reach here if there is a timeout */ + errors = 1; + printf("ERROR: Test %s failed.\n Timed out after %d secs (probably infinite loop)\n", t->name, timeout_limit); return errors; - } - else { - /* if necessary, iterate over vals for third arg */ - for (a3 = 0; a3 < test_counts[2]; a3++) { - errors += test_3_arg(t->solution_funct, - t->test_funct, - arg_test_vals[0][a1], - arg_test_vals[1][a2], - arg_test_vals[2][a3], - t->name); - + } + alarm(timeout_limit); + } + + /* Test function has no arguments */ + if (args == 0) + { + errors += test_0_arg(t->solution_funct, t->test_funct, t->name); + return errors; + } + + /* + * Test function has at least one argument + */ + + /* Iterate over the values for first argument */ + + for (a1 = 0; a1 < test_counts[0]; a1++) + { + if (args == 1) + { + errors += test_1_arg(t->solution_funct, + t->test_funct, + arg_test_vals[0][a1], + t->name); + /* Stop testing if there is an error */ if (errors) - return errors; - } /* a3 */ + return errors; } - } /* a2 */ - } - } /* a1 */ + else + { + /* if necessary, iterate over values for second argument */ + for (a2 = 0; a2 < test_counts[1]; a2++) + { + if (args == 2) + { + errors += test_2_arg(t->solution_funct, + t->test_funct, + arg_test_vals[0][a1], + arg_test_vals[1][a2], + t->name); + + /* Stop testing if there is an error */ + if (errors) + return errors; + } + else + { + /* if necessary, iterate over vals for third arg */ + for (a3 = 0; a3 < test_counts[2]; a3++) + { + errors += test_3_arg(t->solution_funct, + t->test_funct, + arg_test_vals[0][a1], + arg_test_vals[1][a2], + arg_test_vals[2][a3], + t->name); + + /* Stop testing if there is an error */ + if (errors) + return errors; + } /* a3 */ + } + } /* a2 */ + } + } /* a1 */ - - return errors; + return errors; } -/* - * run_tests - Run series of tests. Return number of errors - */ -static int run_tests() +/* + * run_tests - Run series of tests. Return number of errors + */ +static int run_tests() { - int i; - int errors = 0; - double points = 0.0; - double max_points = 0.0; - - printf("Score\tRating\tErrors\tFunction\n"); - - for (i = 0; test_set[i].solution_funct; i++) { - int terrors; - double tscore; - double tpoints; - if (!test_fname || strcmp(test_set[i].name,test_fname) == 0) { - int rating = global_rating ? global_rating : test_set[i].rating; - terrors = test_function(&test_set[i]); - errors += terrors; - tscore = terrors == 0 ? 1.0 : 0.0; - tpoints = rating * tscore; - points += tpoints; - max_points += rating; - - if (grade || terrors < 1) - printf(" %.0f\t%d\t%d\t%s\n", - tpoints, rating, terrors, test_set[i].name); - + int i; + int errors = 0; + double points = 0.0; + double max_points = 0.0; + + printf("Score\tRating\tErrors\tFunction\n"); + + for (i = 0; test_set[i].solution_funct; i++) + { + int terrors; + double tscore; + double tpoints; + if (!test_fname || strcmp(test_set[i].name, test_fname) == 0) + { + int rating = global_rating ? global_rating : test_set[i].rating; + terrors = test_function(&test_set[i]); + errors += terrors; + tscore = terrors == 0 ? 1.0 : 0.0; + tpoints = rating * tscore; + points += tpoints; + max_points += rating; + + if (grade || terrors < 1) + printf(" %.0f\t%d\t%d\t%s\n", + tpoints, rating, terrors, test_set[i].name); + } } - } - printf("Total points: %.0f/%.0f\n", points, max_points); - return errors; + printf("Total points: %.0f/%.0f\n", points, max_points); + return errors; } -/* - * get_num_val - Extract hex/decimal/or float value from string +/* + * get_num_val - Extract hex/decimal/or float value from string */ -static int get_num_val(char *sval, unsigned *valp) { - char *endp; - - /* See if it's an integer or floating point */ - int ishex = 0; - int isfloat = 0; - int i; - for (i = 0; sval[i]; i++) { - switch (sval[i]) { - case 'x': - case 'X': - ishex = 1; - break; - case 'e': - case 'E': - if (!ishex) - isfloat = 1; - break; - case '.': - isfloat = 1; - break; - default: - break; +static int get_num_val(char *sval, unsigned *valp) +{ + char *endp; + + /* See if it's an integer or floating point */ + int ishex = 0; + int isfloat = 0; + int i; + for (i = 0; sval[i]; i++) + { + switch (sval[i]) + { + case 'x': + case 'X': + ishex = 1; + break; + case 'e': + case 'E': + if (!ishex) + isfloat = 1; + break; + case '.': + isfloat = 1; + break; + default: + break; + } } - } - if (isfloat) { - float fval = strtof(sval, &endp); - if (!*endp) { - *valp = *(unsigned *) &fval; - return 1; + if (isfloat) + { + float fval = strtof(sval, &endp); + if (!*endp) + { + *valp = *(unsigned *)&fval; + return 1; + } + return 0; } - return 0; - } else { - long long int llval = strtoll(sval, &endp, 0); - long long int upperbits = llval >> 31; - /* will give -1 for negative, 0 or 1 for positive */ - if (!*valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) { - *valp = (unsigned) llval; - return 1; + else + { + long long int llval = strtoll(sval, &endp, 0); + long long int upperbits = llval >> 31; + /* will give -1 for negative, 0 or 1 for positive */ + if (!*valp && (upperbits == 0 || upperbits == -1 || upperbits == 1)) + { + *valp = (unsigned)llval; + return 1; + } + return 0; } - return 0; - } } - -/* +/* * usage - Display usage info */ -static void usage(char *cmd) { - printf("Usage: %s [-hg] [-r ] [-f [-1|-2|-3 ]*] [-T