From cc4452540dbde80f55d5534ab43f9793c883273e Mon Sep 17 00:00:00 2001 From: Unbewohnte Date: Tue, 10 Jan 2023 15:43:05 +0300 Subject: [PATCH] No need to link math library now; Added abs, pow, sqrt alternatives for projects with no stdlib --- Makefile | 4 +- src/math/misc.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++ src/math/misc.h | 47 ++++++++++++ src/math/vector.c | 8 +-- src/math/vector.h | 2 +- testing/test.c | 41 ++++++++++- 6 files changed, 272 insertions(+), 10 deletions(-) create mode 100644 src/math/misc.c create mode 100644 src/math/misc.h diff --git a/Makefile b/Makefile index 006f3ed..811a7b0 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,13 @@ lib: ar rcs $(BINDIR)/$(LIBNAME) $(BUILDDIR)/*.o test: - $(CC) $(DEFAULTCCFLAGS) $(TESTDIR)/$(TESTBIN).c $(SRCDIR)/*/*.c -o $(TESTDIR)/$(TESTBIN) -lm && \ + $(CC) $(DEFAULTCCFLAGS) $(TESTDIR)/$(TESTBIN).c $(SRCDIR)/*/*.c -o $(TESTDIR)/$(TESTBIN) && \ cd $(TESTDIR) && \ ./$(TESTBIN) && \ rm $(TESTBIN) test_static: lib - $(CC) $(DEFAULTCCFLAGS) $(TESTDIR)/$(TESTBIN).c $(BINDIR)/$(LIBNAME) -static -lm -o $(TESTDIR)/$(TESTBIN) && \ + $(CC) $(DEFAULTCCFLAGS) $(TESTDIR)/$(TESTBIN).c $(BINDIR)/$(LIBNAME) -static -o $(TESTDIR)/$(TESTBIN) && \ cd $(TESTDIR) && \ ./$(TESTBIN) && \ rm $(TESTBIN) diff --git a/src/math/misc.c b/src/math/misc.c new file mode 100644 index 0000000..b7f6a29 --- /dev/null +++ b/src/math/misc.c @@ -0,0 +1,180 @@ +/* +The MIT License (MIT) + +Copyright © 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Returns an absolute value of n +#include "misc.h" + +char absch(char n) { + if (n >= 0) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +short abssh(short n) { + if (n >= 0) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +int absi(int n) { + if (n >= 0) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +long absl(long n) { + if (n >= 0) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +long long absll(long long n) { + if (n >= 0) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +float absf(float n) { + if (n >= 0.0f) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +double absd(double n) { + if (n >= 0.0f) { + return n; + } else { + return -n; + } +} + +// Returns an absolute value of n +long double absld(long double n) { + if (n >= 0.0f) { + return n; + } else { + return -n; + } +} + +long double n_root(long double a, unsigned int n, unsigned int max_iter, long double epsilon) { + if (n == 1 || a == 0) { + return a; + } + + float prev_val = 1; + float val = 0; + + for (unsigned int i = 0; i < max_iter; i++) { + val = (1.0 / n) * ((n - 1) * prev_val + a / powerl(prev_val, n-1)); + + if (absld(prev_val - val) < epsilon) { + return val; + } + + prev_val = val; + } + + return val; +} + +// Returns the approximate result of base^exp +float powerf(float base, float exp) { + // all zeroes|base is zero, but exp is not + if ((base == 0.0f && exp == 0.0f) || (base == 0.0f && exp != 0.0f)) { + return 0.0f; + } + + // exp is 0 + if (exp == 0.0f) { + return 1.0f; + } + + // exp is negative + if (exp < 0.0f) { + return 1.0 / powerf(base, -exp); + } + + // exp is in (0.0; 1.0) + if (exp > 0.0f && exp < 1.0f) { + return (float) n_root(base, 1.0 / exp, 500, 0.00001f); + } + + // exp is even + if ((int) exp % 2 == 0) { + float hpow = powerf(base, exp / 2.0f); + return hpow * hpow; + } + + // exp is integer + return base * powerf(base, exp-1.0); +} + +// Returns the approximate result of base^exp +long double powerl(long double base, long double exp) { + // all zeroes|base is zero, but exp is not + if ((base == 0.0f && exp == 0.0f) || (base == 0.0f && exp != 0.0f)) { + return 0.0f; + } + + // exp is 0 + if (exp == 0.0f) { + return 1.0f; + } + + // exp is negative + if (exp < 0.0f) { + return 1.0 / powerl(base, -exp); + } + + // exp is in (0.0; 1.0) + if (exp > 0.0f && exp < 1.0f) { + return n_root(base, 1.0 / exp, 500, 0.0000000001f); + } + + // exp is even + if ((int) exp % 2 == 0) { + float hpow = powerl(base, exp / 2.0f); + return hpow * hpow; + } + + // exp is integer + return base * powerl(base, exp-1.0); +} + +// Returns the approximate result of square root of n +float sqrootf(float n) { + return powerf(n, 0.5f); +} + +// Returns the approximate result of square root of n +float sqrootl(long double n) { + return powerl(n, 0.5); +} \ No newline at end of file diff --git a/src/math/misc.h b/src/math/misc.h new file mode 100644 index 0000000..892f020 --- /dev/null +++ b/src/math/misc.h @@ -0,0 +1,47 @@ +/* +The MIT License (MIT) + +Copyright © 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Returns an absolute value of n +char absch(char n); + +// Returns an absolute value of n +short abssh(short n); + +// Returns an absolute value of n +int absi(int n); + +// Returns an absolute value of n +long absl(long n); + +// Returns an absolute value of n +long long absll(long long n); + +// Returns an absolute value of n +float absf(float n); + +// Returns an absolute value of n +double absd(double n); + +// Returns an absolute value of n +long double absld(long double n); + +// Returns the approximate result of base^exp +float powerf(float base, float exp); + +// Returns the approximate result of base^exp +long double powerl(long double base, long double exp); + +// Returns the approximate result of square root of n +float sqrootf(float n); + +// Returns the approximate result of square root of n +float sqrootl(long double n); \ No newline at end of file diff --git a/src/math/vector.c b/src/math/vector.c index f0d78b0..b916e7b 100644 --- a/src/math/vector.c +++ b/src/math/vector.c @@ -14,12 +14,12 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I // Calculate vector's length long double vec2_len(vec2 vec) { - return sqrtl((long double) (vec.x*vec.x) + (long double) (vec.y*vec.y)); + return sqrootl((long double) (vec.x*vec.x) + (long double) (vec.y*vec.y)); } // Calculate vector's length long double vec2f_len(vec2f vec) { - return sqrtl(vec.x*vec.x + vec.y*vec.y); + return sqrootl(vec.x*vec.x + vec.y*vec.y); } // Add 2 vectors together @@ -54,7 +54,7 @@ long double vec2f_angle(vec2f a, vec2f b) { // Calculate vector's length long double vec3_len(vec3 vec) { - return sqrt( + return sqrootl( (long double) (vec.x*vec.x) + (long double) (vec.y*vec.y) + (long double) (vec.z*vec.z) @@ -63,7 +63,7 @@ long double vec3_len(vec3 vec) { // Calculate vector's length long double vec3f_len(vec3f vec) { - return sqrtl( + return sqrootl( vec.x*vec.x + vec.y*vec.y + vec.z*vec.z diff --git a/src/math/vector.h b/src/math/vector.h index 045f266..ef2411b 100644 --- a/src/math/vector.h +++ b/src/math/vector.h @@ -10,7 +10,7 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include +#include "misc.h" typedef struct vec2 { long long int x; diff --git a/testing/test.c b/testing/test.c index 0c07fec..bb31709 100644 --- a/testing/test.c +++ b/testing/test.c @@ -1,7 +1,7 @@ /* The MIT License (MIT) -Copyright © 2022 Kasyanov Nikolay Alexeyevich (Unbewohnte) +Copyright © 2022, 2023 Kasyanov Nikolay Alexeyevich (Unbewohnte) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -24,6 +24,7 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I #include "../src/fs/fs.h" #include "../src/bits/bits.h" #include "../src/math/vector.h" +#include "../src/math/misc.h" #include "../src/datastruct/cvec.h" int test_rng() { @@ -176,7 +177,7 @@ int test_vector() { vec2 vec2d_other = {3, 2}; long long int multiplied; - if (fabsl(vec2_len(vec2d) - 3.606f) > threshold) { + if (absld(vec2_len(vec2d) - 3.606f) > threshold) { printf("[ERROR] Vector length calculation is wrong: expeted to be %f (+-%Lf); got %Lf\n", 3.606f, threshold, vec2_len(vec2d) ); @@ -191,7 +192,7 @@ int test_vector() { vec2d = (vec2){3, 4}; vec2d_other = (vec2){4, 3}; - if (fabsl(vec2_angle(vec2d, vec2d_other) - 0.96f) > threshold) { + if (absld(vec2_angle(vec2d, vec2d_other) - 0.96f) > threshold) { printf("[ERROR] Failed to calculate angle between 2 vectors: expected to be %f (+-%Lf); got %Lf\n", 0.96f, threshold, vec2_angle(vec2d, vec2d_other) ); @@ -211,12 +212,46 @@ int test_vector() { return EXIT_SUCCESS; } +int test_misc() { + const float num1 = -0.5; + if (absf(num1) != 0.5f) { + printf("[ERROR] Failed to get absolute value of %f: got %f; expected %f", num1, absf(num1), -num1); + return EXIT_FAILURE; + } + + const float abs_num1_pow2 = absf(num1) * absf(num1); + if (powerf(absf(num1), 2.0f) != abs_num1_pow2) { + printf("[ERROR] Failed to get %f to the power of 2: got %f; expected %f", absf(num1), powerf(absf(num1), 2.0f), abs_num1_pow2); + return EXIT_FAILURE; + } + + const int num2 = 2; + const float result = powerf(powerf(powerf((float) num2, 2.0f), 2.0f), 2.0f); + if (result != 256.0f) { + printf("[ERROR] Failed to get ((%d^2)^2)^2: got %f; expected %d", num2, result, 256); + return EXIT_FAILURE; + } + + const int num3 = 4; + if (sqrootf(num3) != 2.0) { + printf("[ERROR] Failed to calculate square root of %d: got %f; expected %d", num3, sqrootf(num3), 2); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + int test_math() { if (test_vector() == EXIT_FAILURE) { printf("[ERROR] Vector test failed\n"); return EXIT_FAILURE; } + if (test_misc() == EXIT_FAILURE) { + printf("[ERROR] Misc test failed\n"); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; }