From 8c7253039040d82fdafadbee7ac4a7b67672ab43 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Mon, 16 Jun 2025 22:15:20 +0300 Subject: [PATCH] implement taylor series tests --- src/math_func_checker.c | 111 ++++++++++++++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 16 deletions(-) diff --git a/src/math_func_checker.c b/src/math_func_checker.c index d46ace6..155dda6 100644 --- a/src/math_func_checker.c +++ b/src/math_func_checker.c @@ -5,9 +5,15 @@ typedef double f64; typedef float f32; +typedef uint64_t u64; typedef f64 (*math_func)(f64); #define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) +struct tester { + f64 max_error; + f64 max_error_at; +}; + struct math_spec { const char *name; math_func mine; @@ -80,6 +86,11 @@ static f64 my_sin_quarter_fitted(f64 num) return result * sign; } +static f64 my_cos_using_sin(f64 num) +{ + return my_sin_quarter_fitted(num + M_PI/2); +} + static f64 my_cos(f64 num) { if (num < 0) { @@ -113,6 +124,74 @@ static f64 my_asin(f64 num) return num; } +static f64 factorial(size_t n) +{ + f64 result = 1; + for (size_t i = 1; i <= n; i++) { + result *= i; + } + return result; +} + +static void create_taylor_series_coeffs(f64 *coeffs, size_t coeffs_len) +{ + for (size_t i = 0; i < coeffs_len; i++) { + size_t n = 1 + (i*2); + coeffs[i] = 1 / factorial(n); + if (i % 2 == 1) { + coeffs[i] *= -1; + } + } +} + +static f64 sin_using_taylor(f64 input, f64 *coeffs, size_t coeffs_len) +{ + f64 result = 0; + for (size_t i = 0; i < coeffs_len; i++) { + f64 power = 1 + (i*2); + result += coeffs[i] * powf(input, power); + } + return result; +} + +static void tester_record_result(struct tester *tester, f64 input, f64 my_output, f64 reference_output) +{ + f64 error = reference_output - my_output; + if (error < 0) { + error = -error; + } + + if (error > tester->max_error) { + tester->max_error = error; + tester->max_error_at = input; + } +} + +static void tester_show_result(struct tester *tester, const char *name) +{ + printf("%20s max error %.16f at %f\n", name, tester->max_error, tester->max_error_at); +} + +static f64 lerp(f64 x, f64 from, f64 to) +{ + return (to - from) * x + from; +} + +static void test_taylor_series(u64 samples, f64 *coeffs, size_t coeffs_len) +{ + create_taylor_series_coeffs(coeffs, coeffs_len); + + struct tester tester = { }; + for (int j = 0; j < samples; j++) { + f64 input = lerp((f64)j / samples, -M_PI, M_PI); + tester_record_result(&tester, input, sin_using_taylor(input, coeffs, coeffs_len), sin(input)); + } + + char name[64] = { 0 }; + snprintf(name, sizeof(name), "taylor %zu", coeffs_len); + tester_show_result(&tester, name); +} + int main() { uint64_t samples = 10000; @@ -138,6 +217,13 @@ int main() .from = -M_PI, .to = M_PI }, + { + .name = "my_cos_using_sin", + .mine = my_cos_using_sin, + .reference = cos, + .from = -M_PI, + .to = M_PI + }, { .name = "cos", .mine = my_cos, @@ -171,26 +257,19 @@ int main() for (int i = 0; i < ARRAY_LEN(specs); i++) { struct math_spec spec = specs[i]; - f64 max_error = 0; - f64 max_error_at = 0; + struct tester tester = { }; for (int j = 0; j < samples; j++) { - f64 input = ((f64)j / samples) * (spec.to - spec.from) + spec.from; - f64 reference_output = spec.reference(input); - f64 my_output = spec.mine(input); - - f64 error = reference_output - my_output; - if (error < 0) { - error = -error; - } - - if (error > max_error) { - max_error = error; - max_error_at = input; - } + f64 input = lerp((f64)j / samples, spec.from, spec.to); + tester_record_result(&tester, input, spec.mine(input), spec.reference(input)); } - printf("%20s max error %f at %f\n", spec.name, max_error, max_error_at); + tester_show_result(&tester, spec.name); + } + + f64 taylor_coeffs[41]; + for (int i = 3; i < ARRAY_LEN(taylor_coeffs); i++) { + test_taylor_series(samples, taylor_coeffs, i); } return 0;