#include #include #include #include #include #include #define STR_RED "\x1b[31m" #define STR_GREEN "\x1b[32m" #define STR_NORM "\x1b[m" #define SECONDS_PER_NANOSECOND 1000000000 #define NUM_STATS 100000 #define SQRT_NUM_STATS 100 #define NUM_LOOPS 10000000 struct circle { double c; double s; }; #ifdef USE_COMPLEX #define EXTRACT_COSINE(a) creal(a) #define EXTRACT_SINE(a) cimag(a) #define CIRCLE_TYPE double complex #else #define EXTRACT_COSINE(a) (a.c) #define EXTRACT_SINE(a) (a.s) #define CIRCLE_TYPE struct circle #endif void turn_update(double turn, CIRCLE_TYPE* result); void approx_turn_update(double turn, CIRCLE_TYPE* result); void print_errors( const double* inputs, const CIRCLE_TYPE* ideals, const CIRCLE_TYPE* approxs, int n ) { double c_error, s_error; double largest_c_error = 0, largest_s_error = 0; size_t largest_c_index, largest_s_index; double total_c_error = 0, total_s_error = 0; size_t i; CIRCLE_TYPE ideal, approx; for (i = 0; i < n; i++) { ideal = ideals[i]; approx = approxs[i]; // squared error in c components c_error = EXTRACT_COSINE(ideal) - EXTRACT_COSINE(approx); c_error *= c_error; // squared error in s components s_error = EXTRACT_SINE(ideal) - EXTRACT_SINE(approx); s_error *= s_error; if (largest_c_error < c_error) { largest_c_error = c_error; largest_c_index = i; } if (largest_s_error < s_error) { largest_s_error = s_error; largest_s_index = i; } total_c_error += c_error; total_s_error += s_error; } // these now contain the *average* squared error total_c_error /= (double)n; total_s_error /= (double)n; printf( "Squared error in cosines (%d runs): \n" "\tAverage: %f (%f%% error)\n" "\tLargest: %f (%f%% error)\n" "\t\tInput:\t\t%f\n" "\t\tValue:\t\t%f\n" "\t\tApproximation:\t%f\n", NUM_STATS, total_c_error, sqrt(total_c_error) * SQRT_NUM_STATS, largest_c_error, sqrt(largest_c_error) * SQRT_NUM_STATS, inputs[largest_c_index], EXTRACT_COSINE(ideals[largest_c_index]), EXTRACT_COSINE(approxs[largest_c_index]) ); printf( "Squared error in sines (%d runs): \n" "\tAverage: %f (%f%% error)\n" "\tLargest: %f (%f%% error)\n" "\t\tInput:\t\t%f\n" "\t\tValue:\t\t%f\n" "\t\tApproximation:\t%f\n", NUM_STATS, total_s_error, sqrt(total_s_error) * SQRT_NUM_STATS, largest_s_error, sqrt(largest_s_error) * SQRT_NUM_STATS, inputs[largest_s_index], EXTRACT_SINE(ideals[largest_s_index]), EXTRACT_SINE(approxs[largest_s_index]) ); } // time the length of the computation `f` in nanoseconds // using a macro rather than a function taking a function pointer for // more accurate time #define TIME_COMPUTATION(f, inputs, results, n_stats, n_loop, time) \ do { \ size_t i; \ struct timespec tp1; \ struct timespec tp2; \ \ for (i = 0; i < n_stats; i++) { \ f(inputs[i], results + i); \ } \ CIRCLE_TYPE temp; \ clock_gettime(CLOCK_MONOTONIC, &tp1); \ for (i = 0; i < n_stats; i++) { \ f(rand() / (double)RAND_MAX, &temp); \ } \ clock_gettime(CLOCK_MONOTONIC, &tp2); \ \ time = SECONDS_PER_NANOSECOND * (tp2.tv_sec - tp1.tv_sec) + \ (tp2.tv_nsec - tp1.tv_nsec); \ } while (0) int main(int argn, char** args) { long trig_time, rat_time; double rands[NUM_STATS]; CIRCLE_TYPE trigs[NUM_STATS]; CIRCLE_TYPE rats[NUM_STATS]; size_t i; for (i = 0; i < NUM_STATS; i++) { rands[i] = rand() / (double)RAND_MAX; } TIME_COMPUTATION( turn_update, rands, trigs, NUM_STATS, NUM_LOOPS, trig_time ); printf( #ifdef USE_COMPLEX "Timing for %d complex.h cexp:\t%ldns\n", #else "Timing for %d math.h sin and cos:\t%ldns\n", #endif NUM_LOOPS, trig_time ); TIME_COMPUTATION( approx_turn_update, rands, rats, NUM_STATS, NUM_LOOPS, rat_time ); printf("Timing for %d approximations:\t%ldns\n", NUM_LOOPS, rat_time); // Report results long diff = rat_time - trig_time; double frac_speed; if (diff > 0) { frac_speed = rat_time / (double)trig_time; // Disable colors for non-terminal output if (isatty(STDOUT_FILENO)) { printf( STR_RED "stdlib" STR_NORM " faster, speedup: %ldns (%2.2fx)\n", diff, frac_speed ); } else { printf( "stdlib faster, speedup: %ldns (%2.2fx)\n", diff, frac_speed ); } } else { frac_speed = trig_time / (double)rat_time; // Disable colors for non-terminal output if (isatty(STDOUT_FILENO)) { printf( STR_GREEN "Approximation" STR_NORM " faster, speedup: %ldns (%2.2fx)\n", -diff, frac_speed ); } else { printf( "Approximation faster, speedup: %ldns (%2.2fx)\n", -diff, frac_speed ); } print_errors(rands, trigs, rats, NUM_STATS); } return 0; }