diff --git a/libc3/ratio.c b/libc3/ratio.c
index 191da23..30f23c4 100644
--- a/libc3/ratio.c
+++ b/libc3/ratio.c
@@ -20,9 +20,9 @@
#include "integer.h"
#include "ratio.h"
-s_ratio * ratio_add (const s_ratio *a, const s_ratio *b,
- s_ratio *dest)
+s_ratio * ratio_add (const s_ratio *a, const s_ratio *b, s_ratio *dest)
{
+ s_ratio tmp;
s_integer i;
s_integer j;
assert(a);
@@ -30,13 +30,22 @@ s_ratio * ratio_add (const s_ratio *a, const s_ratio *b,
assert(dest);
assert(integer_is_positive(&a->denominator));
assert(integer_is_positive(&b->denominator));
+ if (! integer_init(&tmp.numerator) || ! integer_init(&tmp.denominator)) {
+ err_puts("ratio_add: failed to initialize numerator or denominator");
+ return NULL;
+ }
integer_mul(&a->numerator, &b->denominator, &i);
integer_mul(&b->numerator, &a->denominator, &j);
- integer_add(&i, &j, &dest->numerator);
- integer_mul(&a->denominator, &b->denominator,
- &dest->denominator);
+ integer_add(&i, &j, &tmp.numerator);
+ integer_mul(&a->denominator, &b->denominator, &tmp.denominator);
integer_clean(&i);
integer_clean(&j);
+ if (! ratio_simplify(&tmp, dest)) {
+ err_puts("ratio_add: failed to simplify ratio");
+ ratio_clean(&tmp);
+ return NULL;
+ }
+ ratio_clean(&tmp);
return dest;
}
@@ -205,6 +214,34 @@ s_ratio * ratio_neg (const s_ratio *r, s_ratio *dest)
return dest;
}
+s_ratio * ratio_simplify(s_ratio *r, s_ratio *dest)
+{
+ s_ratio tmp;
+ s_integer gcd;
+ assert(r);
+ assert(dest);
+ if (! integer_init(&tmp.numerator) || ! integer_init(&tmp.denominator)) {
+ err_puts("ratio_simplify: failed to initialize numerator or denominator");
+ return NULL;
+ }
+ integer_gcd(&r->numerator, &r->denominator, &gcd);
+ if (! integer_div(&r->numerator, &gcd, &tmp.numerator)) {
+ err_puts("ratio_simplify: failed to divide numerator by gcd");
+ integer_clean(&tmp.numerator);
+ integer_clean(&tmp.denominator);
+ return NULL;
+ }
+ if (! integer_div(&r->denominator, &gcd, &tmp.denominator)) {
+ err_puts("ratio_simplify: failed to divide denominator by gcd");
+ integer_clean(&tmp.numerator);
+ integer_clean(&tmp.denominator);
+ return NULL;
+ }
+ integer_clean(&gcd);
+ *dest = tmp;
+ return dest;
+}
+
s_tag * ratio_sqrt (const s_ratio *r, s_tag *dest)
{
s_ratio tmp = {0};
diff --git a/libc3/ratio.h b/libc3/ratio.h
index 1f4aff2..241d161 100644
--- a/libc3/ratio.h
+++ b/libc3/ratio.h
@@ -64,4 +64,6 @@ s_ratio * ratio_sub (const s_ratio *a, const s_ratio *b,
/* Setters. */
s_ratio * ratio_set_double (s_ratio *a, double x);
+s_ratio * ratio_simplify(s_ratio *r, s_ratio *dest);
+
#endif /* LIBC3_RATIO_H */
diff --git a/libc3/tag_add.c b/libc3/tag_add.c
index 4449bd1..1d26e2e 100644
--- a/libc3/tag_add.c
+++ b/libc3/tag_add.c
@@ -12,6 +12,7 @@
*/
#include "assert.h"
#include "integer.h"
+#include "ratio.h"
#include "tag.h"
s_tag * tag_add (const s_tag *a, const s_tag *b, s_tag *dest)
@@ -162,6 +163,15 @@ s_tag * tag_add (const s_tag *a, const s_tag *b, s_tag *dest)
default:
goto ko;
}
+ case TAG_RATIO:
+ switch (b->type) {
+ case TAG_RATIO:
+ dest->type = TAG_RATIO;
+ ratio_add(&a->data.ratio, &b->data.ratio, &dest->data.ratio);
+ return dest;
+ default:
+ goto ko;
+ }
case TAG_S8:
switch (b->type) {
case TAG_F32: