diff --git a/src/test_eressea.c b/src/test_eressea.c index 4ffe1f19c..1d991725f 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -6,6 +6,7 @@ #include #include #include +#include #pragma warning(disable: 4210) @@ -85,6 +86,7 @@ int RunAllTests(int argc, char *argv[]) ADD_SUITE(unicode); ADD_SUITE(strings); ADD_SUITE(log); + ADD_SUITE(variant); ADD_SUITE(rng); /* items */ ADD_SUITE(xerewards); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 743ff4d88..91ed118ae 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -28,6 +28,7 @@ log.test.c # translation.test.c umlaut.test.c unicode.test.c +variant.test.c # xml.test.c ) diff --git a/src/util/variant.c b/src/util/variant.c index e3461f861..74d7adb1c 100644 --- a/src/util/variant.c +++ b/src/util/variant.c @@ -1,16 +1,39 @@ +#include #include "variant.h" + +#include #include -static int lcd(int a, int b) { - return a * b; +static int gcd(int a, int b) { + const int primes[] = { 3, 5, 7, 11, 13, 17, 19, 23, 0 }; + int i = 0, g = 1, p = 2; + while (p && p <= a && p <= b) { + if (a % p == 0 && b % p == 0) { + a /= p; + b /= p; + g *= p; + } + else { + p = primes[i++]; + } + } + return g; } -variant frac_add(variant a, variant b) +static int lcm(int a, int b) { + int x; + if (a == b) return a; + x = (a * b); + x = (x > 0 ? x : -x) / gcd(a, b); + return x; +} + +variant frac_make(int num, int den) { - int num, den; variant v; - den = lcd(a.sa[1], b.sa[1]); - num = a.sa[0] * lcd / a.sa[1] + b.sa[0] * lcd / b.sa[1]; + int g = gcd(num, den); + num /= g; + den /= g; assert(num >= SHRT_MIN && num <= SHRT_MAX); assert(den >= SHRT_MIN && den <= SHRT_MAX); v.sa[0] = (short)num; @@ -18,19 +41,20 @@ variant frac_add(variant a, variant b) return v; } +variant frac_add(variant a, variant b) +{ + int num, den; + den = lcm(a.sa[1], b.sa[1]); + num = a.sa[0] * den / a.sa[1] + b.sa[0] * den / b.sa[1]; + return frac_make(num, den); +} + variant frac_mul(variant a, variant b) { - variant v = a; - return v; + return frac_make(a.sa[0] * b.sa[0], a.sa[1] * b.sa[1]); } variant frac_div(variant a, variant b) { - variant v = a; - return v; + return frac_make(a.sa[0] * b.sa[1], a.sa[1] * b.sa[0]); } - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/util/variant.h b/src/util/variant.h index 8c78bc3ac..f98fa0b80 100644 --- a/src/util/variant.h +++ b/src/util/variant.h @@ -21,6 +21,7 @@ extern "C" { VAR_FLOAT } variant_type; + variant frac_make(int num, int den); variant frac_add(variant a, variant b); variant frac_mul(variant a, variant b); variant frac_div(variant a, variant b); diff --git a/src/util/variant.test.c b/src/util/variant.test.c new file mode 100644 index 000000000..6344e5c33 --- /dev/null +++ b/src/util/variant.test.c @@ -0,0 +1,28 @@ +#include +#include "variant.h" + +#include + +static void test_fractions(CuTest *tc) { + variant a, b; + a = frac_make(120, 12000); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 100, a.sa[1]); + b = frac_make(23, 2300); + a = frac_add(a, b); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 50, a.sa[1]); + a = frac_mul(a, b); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 5000, a.sa[1]); + a = frac_div(b, b); + CuAssertIntEquals(tc, 1, a.sa[0]); + CuAssertIntEquals(tc, 1, a.sa[1]); +} + +CuSuite *get_variant_suite(void) +{ + CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_fractions); + return suite; +}