diff --git a/posts/stereo/1/Makefile b/posts/stereo/1/Makefile deleted file mode 100644 index 5cfffc1..0000000 --- a/posts/stereo/1/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -default: compare_complex compare_math - -clean: - rm -rf compare_complex compare_math - -compare_complex: - gcc main.c stereo_complex.c -lm -DUSE_COMPLEX -o compare_complex - -compare_math: - gcc main.c stereo_math.c -lm -o compare_math diff --git a/posts/stereo/1/.clang-format b/posts/stereo/1/approx-results/.clang-format similarity index 100% rename from posts/stereo/1/.clang-format rename to posts/stereo/1/approx-results/.clang-format diff --git a/posts/stereo/1/.gitignore b/posts/stereo/1/approx-results/.gitignore similarity index 100% rename from posts/stereo/1/.gitignore rename to posts/stereo/1/approx-results/.gitignore diff --git a/posts/stereo/1/approx-results/Makefile b/posts/stereo/1/approx-results/Makefile new file mode 100644 index 0000000..757487b --- /dev/null +++ b/posts/stereo/1/approx-results/Makefile @@ -0,0 +1,14 @@ +default: report + +clean: + rm -rf compare_complex compare_math results_complex.txt results_math.txt + +report: compare_complex compare_math + ./compare_complex > results_complex.txt + ./compare_math > results_math.txt + +compare_complex: + gcc main.c stereo_complex.c -lm -DUSE_COMPLEX -o compare_complex + +compare_math: + gcc main.c stereo_math.c -lm -o compare_math diff --git a/posts/stereo/1/approx-results/main.c b/posts/stereo/1/approx-results/main.c new file mode 100644 index 0000000..db1e705 --- /dev/null +++ b/posts/stereo/1/approx-results/main.c @@ -0,0 +1,196 @@ +#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; +} diff --git a/posts/stereo/1/approx-results/results_complex.txt b/posts/stereo/1/approx-results/results_complex.txt new file mode 100644 index 0000000..27b4634 --- /dev/null +++ b/posts/stereo/1/approx-results/results_complex.txt @@ -0,0 +1,15 @@ +Timing for 10000000 complex.h cexp: 2864133ns +Timing for 10000000 approximations: 1321049ns +Approximation faster, speedup: 1543084ns (2.17x) +Squared error in cosines (100000 runs): + Average: 0.000051 (0.713743% error) + Largest: 0.000174 (1.320551% error) + Input: 0.729202 + Value: -0.659428 + Approximation: -0.672634 +Squared error in sines (100000 runs): + Average: 0.000070 (0.835334% error) + Largest: 0.000288 (1.698413% error) + Input: 0.842206 + Value: 0.475669 + Approximation: 0.458685 diff --git a/posts/stereo/1/approx-results/results_math.txt b/posts/stereo/1/approx-results/results_math.txt new file mode 100644 index 0000000..11dbb60 --- /dev/null +++ b/posts/stereo/1/approx-results/results_math.txt @@ -0,0 +1,15 @@ +Timing for 10000000 math.h sin and cos: 2822266ns +Timing for 10000000 approximations: 1223832ns +Approximation faster, speedup: 1598434ns (2.31x) +Squared error in cosines (100000 runs): + Average: 0.000051 (0.713743% error) + Largest: 0.000174 (1.320551% error) + Input: 0.729202 + Value: -0.659428 + Approximation: -0.672634 +Squared error in sines (100000 runs): + Average: 0.000070 (0.835334% error) + Largest: 0.000288 (1.698413% error) + Input: 0.842206 + Value: 0.475669 + Approximation: 0.458685 diff --git a/posts/stereo/1/stereo_complex.c b/posts/stereo/1/approx-results/stereo_complex.c similarity index 100% rename from posts/stereo/1/stereo_complex.c rename to posts/stereo/1/approx-results/stereo_complex.c diff --git a/posts/stereo/1/stereo_math.c b/posts/stereo/1/approx-results/stereo_math.c similarity index 100% rename from posts/stereo/1/stereo_math.c rename to posts/stereo/1/approx-results/stereo_math.c diff --git a/posts/stereo/1/main.c b/posts/stereo/1/main.c deleted file mode 100644 index 28d2768..0000000 --- a/posts/stereo/1/main.c +++ /dev/null @@ -1,174 +0,0 @@ -#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; -}