Commit 3c8e3c8c66a8509087670ea7a072abac7ee00f97

Thomas de Grivel 2024-03-04T11:49:26

wip ratio

diff --git a/libc3/ratio.c b/libc3/ratio.c
index e92f02c..27fcde9 100644
--- a/libc3/ratio.c
+++ b/libc3/ratio.c
@@ -78,14 +78,35 @@ void ratio_clean (s_ratio *r)
 s_ratio * ratio_div (const s_ratio *a, const s_ratio *b,
                            s_ratio *dest)
 {
+  s_ratio tmp = {0};
+  s_ratio tmp2 = {0};
   assert(a);
   assert(b);
   assert(dest);
   assert(! integer_is_zero(&b->numerator));
   assert(integer_is_positive(&a->denominator));
   assert(integer_is_positive(&b->denominator));
-  integer_mul(&a->numerator, &b->denominator, &dest->numerator);
-  integer_mul(&a->denominator, &b->numerator, &dest->denominator);
+  if (! integer_mul(&a->numerator, &b->denominator, &tmp.numerator))
+    return NULL;
+  if (! integer_mul(&a->denominator, &b->numerator, &tmp.denominator)) {
+    integer_clean(&tmp.numerator);
+    return NULL;
+  }
+  if (integer_is_negative(&tmp.denominator)) {
+    if (! integer_neg(&tmp.numerator, &tmp2.numerator)) {
+      ratio_clean(&tmp);
+      return NULL;
+    }
+    if (! integer_neg(&tmp.denominator, &tmp2.denominator)) {
+      integer_clean(&tmp2.numerator);
+      ratio_clean(&tmp);
+      return NULL;
+    }
+    *dest = tmp2;
+    ratio_clean(&tmp);
+  }
+  else
+    *dest = tmp;
   return dest;
 }
 
@@ -118,13 +139,13 @@ s_ratio * ratio_init_1 (s_ratio *q, const char *p)
   buf.wpos = len;
   r = buf_parse_ratio(&buf, &tmp);
   if (r < 0 || (uw) r != len) {
-    err_write_1("invalid ratio: \"");
+    err_write_1("ratio_init_1: invalid ratio: \"");
     err_write_1(p);
     err_write_1("\", ");
     err_inspect_uw(&len);
     err_write_1(" != ");
     err_inspect_sw(&r);
-    assert(! "invalid ratio");
+    assert(! "ratio_init_1: invalid ratio");
     return NULL;
   }
   *q = tmp;
@@ -133,12 +154,16 @@ s_ratio * ratio_init_1 (s_ratio *q, const char *p)
 
 s_ratio * ratio_init_copy (s_ratio *dest, const s_ratio *src)
 {
+  s_ratio tmp = {0};
   assert(src);
   assert(dest);
-  if (integer_init_copy(&dest->numerator, &src->numerator) == NULL)
+  if (! integer_init_copy(&tmp.numerator, &src->numerator))
     return NULL;
-  if (integer_init_copy(&dest->denominator, &src->denominator) == NULL)
+  if (! integer_init_copy(&tmp.denominator, &src->denominator)) {
+    integer_clean(&tmp.numerator);
     return NULL;
+  }
+  *dest = tmp;
   return dest;
 }
 
@@ -226,9 +251,9 @@ s_ratio * ratio_mul (const s_ratio *a, const s_ratio *b,
   assert(dest);
   assert(integer_is_positive(&a->denominator));
   assert(integer_is_positive(&b->denominator));
-  integer_mul(&a->numerator, &b->numerator, &dest->numerator);
+  integer_mul(&a->numerator, &b->numerator, &tmp.numerator);
   integer_mul(&a->denominator, &b->denominator,
-          &dest->denominator);
+          &tmp.denominator);
   return dest;
 }
 
@@ -304,19 +329,49 @@ s_tag * ratio_sqrt (const s_ratio *r, s_tag *dest)
 s_ratio * ratio_sub (const s_ratio *a, const s_ratio *b,
                            s_ratio *dest)
 {
+  s_ratio tmp;
+  s_integer i;
+  s_integer j;
   assert(a);
   assert(b);
   assert(dest);
-  assert(!integer_is_zero(&a->denominator));
-  assert(!integer_is_zero(&b->denominator));
-
-  s_integer temp1, temp2;
-  integer_mul(&a->numerator, &b->denominator, &temp1);
-  integer_mul(&b->numerator, &a->denominator, &temp2);
-  integer_sub(&temp1, &temp2, &dest->numerator);
-  integer_mul(&a->denominator, &b->denominator,
-          &dest->denominator);
-
+  assert(integer_is_positive(&a->denominator));
+  assert(integer_is_positive(&b->denominator));
+  if (! integer_init(&tmp.numerator))
+    return NULL;
+  if (! integer_init(&tmp.denominator)) {
+    integer_clean(&tmp.numerator);
+    return NULL;
+  }
+  if (! integer_mul(&a->numerator, &b->denominator, &i)) {
+    ratio_clean(&tmp);
+    return NULL;
+  }
+  if (! integer_mul(&b->numerator, &a->denominator, &j)) {
+    integer_clean(&i);
+    ratio_clean(&tmp);
+    return NULL;
+  }
+  if (! integer_sub(&i, &j, &tmp.numerator)) {
+    integer_clean(&i);
+    integer_clean(&j);
+    ratio_clean(&tmp);
+    return NULL;
+  }
+  if (! integer_mul(&a->denominator, &b->denominator,
+                    &tmp.denominator)) {
+    integer_clean(&i);
+    integer_clean(&j);
+    ratio_clean(&tmp);
+    return NULL;
+  }
+  integer_clean(&i);
+  integer_clean(&j);
+  if (! ratio_simplify(&tmp, dest)) {
+    ratio_clean(&tmp);
+    return NULL;
+  }
+  ratio_clean(&tmp);
   return dest;
 }