Commit df4d9d89f0c1ea6ea9e8b94d6445cf7104860c28

Baptiste 2024-03-01T14:36:29

first working ratio add with simplify

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: