#include #include #include #include #include #define STRRED "\x1b[31m" #define STRGREEN "\x1b[32m" #define STRNORM "\x1b[m" #define SECONDS_PER_NANOSECOND 1000000000 #define NUM_LOOPS 100000 double complex complex_turn(double turn) { return cexp(I * M_PI * turn); } double complex approx_turn(double turn) { const static double a = 8 * M_SQRT2 / 3 - 3; const static double b = 4 - 8 * M_SQRT2 / 3; double p = turn * (b * turn * turn + a); double q = p * p; double r = 1 + q; double c = (1 - q) / r, s = 2 * p / r; return (c * c - s * s) + I * (2 * c * s); } void print_errors( const double* inputs, const double complex* ideals, const double complex* approxs, int n ) { double c_error, s_error; double largest_c_error, largest_s_error; size_t largest_c_index, largest_s_index; double total_c_error = 0, total_s_error = 0; size_t i; double complex ideal, approx; for (i = 0; i < n; i++) { ideal = ideals[i]; approx = approxs[i]; // squared error in c components c_error = creal(ideal) - creal(approx); c_error *= c_error; // squared error in s components s_error = cimag(ideal) - cimag(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: \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", total_c_error, sqrt(total_c_error) * 100, largest_c_error, sqrt(largest_c_error) * 100, inputs[largest_c_index], creal(ideals[largest_c_index]), creal(approxs[largest_c_index]) ); printf( "Squared error in sines: \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", total_s_error, sqrt(total_s_error) * 100, largest_s_error, sqrt(largest_s_error) * 100, inputs[largest_c_index], cimag(ideals[largest_s_index]), cimag(approxs[largest_s_index]) ); } // time the length of the computation `f` in nanoseconds long time_computation( double complex (*f)(double), const double* inputs, double complex* results, int n ) { size_t i; long tick_s; long tick_ns; struct timespec tp; clock_gettime(CLOCK_MONOTONIC, &tp); tick_ns = tp.tv_nsec; tick_s = tp.tv_sec; for (i = 0; i < n; i++) { results[i] = f(inputs[i]); } clock_gettime(CLOCK_MONOTONIC, &tp); return SECONDS_PER_NANOSECOND * (tp.tv_sec - tick_s) + (tp.tv_nsec - tick_ns); } int main(int argn, char** args) { long trig_time, rat_time; double rands[NUM_LOOPS]; double complex trigs[NUM_LOOPS]; double complex rats[NUM_LOOPS]; size_t i; for (i = 0; i < NUM_LOOPS; i++) { rands[i] = rand() / (double)RAND_MAX; } trig_time = time_computation(&complex_turn, rands, trigs, NUM_LOOPS); printf("Timing for %d math.h sin and cos:\t%ldns\n", NUM_LOOPS, trig_time); rat_time = time_computation(&approx_turn, rands, rats, NUM_LOOPS); printf("Timing for %d approximations:\t%ldns\n", NUM_LOOPS, rat_time); long diff = rat_time - trig_time; double frac_speed; if (diff > 0) { frac_speed = rat_time / (double)trig_time; printf( STRRED "math.h" STRNORM " faster, speedup: %ldns (%2.2fx)\n", diff, frac_speed ); } else { frac_speed = trig_time / (double)rat_time; printf( STRGREEN "Approximation" STRNORM " faster, speedup: %ldns (%2.2fx)\n", -diff, frac_speed ); print_errors(rands, trigs, rats, NUM_LOOPS); } return 0; }