fixes for stereographic approximation reporting

This commit is contained in:
queue-miscreant 2025-07-22 02:37:59 -05:00
parent 86938469af
commit b2b2dd4e04

View File

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