utils: Fix GMP scaling unit test
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 15 Sep 2009 07:41:28 +0000 (09:41 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Tue, 15 Sep 2009 09:31:15 +0000 (11:31 +0200)
GMP only uses "unsigned long int", which is 32 bit
on 32 bit architectures and can't hold a guint64.
This resulted in false unit test failures on 32 bit architectures.

Fixes bug #595133.

tests/check/gst/gstutils.c

index e7a29df..69d0222 100644 (file)
@@ -774,32 +774,84 @@ enum round_t
   ROUND_DOWN
 };
 
+static void
+gmp_set_uint64 (mpz_t mp, guint64 x)
+{
+  mpz_t two_32, tmp;
+
+  mpz_init (two_32);
+  mpz_init (tmp);
+
+  mpz_ui_pow_ui (two_32, 2, 32);
+  mpz_set_ui (mp, (unsigned long) ((x >> 32) & G_MAXUINT32));
+  mpz_mul (tmp, mp, two_32);
+  mpz_add_ui (mp, tmp, (unsigned long) (x & G_MAXUINT32));
+  mpz_clear (two_32);
+  mpz_clear (tmp);
+}
+
+static guint64
+gmp_get_uint64 (mpz_t mp)
+{
+  mpz_t two_64, two_32, tmp;
+  guint64 ret;
+
+  mpz_init (two_64);
+  mpz_init (two_32);
+  mpz_init (tmp);
+
+  mpz_ui_pow_ui (two_64, 2, 64);
+  mpz_ui_pow_ui (two_32, 2, 32);
+  if (mpz_cmp (tmp, two_64) >= 0)
+    return G_MAXUINT64;
+  mpz_clear (two_64);
+
+  mpz_tdiv_q (tmp, mp, two_32);
+  ret = mpz_get_ui (tmp);
+  ret <<= 32;
+  ret |= mpz_get_ui (mp);
+  mpz_clear (two_32);
+  mpz_clear (tmp);
+
+  return ret;
+}
+
 static guint64
 gmp_scale (guint64 x, guint64 a, guint64 b, enum round_t mode)
 {
-  mpz_t mp1, mp2;
+  mpz_t mp1, mp2, mp3;
   if (!b)
     /* overflow */
     return G_MAXUINT64;
-  mpz_init_set_ui (mp1, x);
+  mpz_init (mp1);
   mpz_init (mp2);
-  mpz_mul_ui (mp2, mp1, a);
+  mpz_init (mp3);
+
+  gmp_set_uint64 (mp1, x);
+  gmp_set_uint64 (mp3, a);
+  mpz_mul (mp2, mp1, mp3);
   switch (mode) {
     case ROUND_TONEAREST:
-      mpz_add_ui (mp1, mp2, b / 2);
+      gmp_set_uint64 (mp1, b);
+      mpz_tdiv_q_ui (mp3, mp1, 2);
+      mpz_add (mp1, mp2, mp3);
       mpz_set (mp2, mp1);
       break;
     case ROUND_UP:
-      mpz_add_ui (mp1, mp2, b - 1);
+      gmp_set_uint64 (mp1, b);
+      mpz_sub_ui (mp3, mp1, 1);
+      mpz_add (mp1, mp2, mp3);
       mpz_set (mp2, mp1);
       break;
     case ROUND_DOWN:
       break;
   }
-  mpz_tdiv_q_ui (mp1, mp2, b);
-  x = mpz_get_ui (mp1);
+  gmp_set_uint64 (mp3, b);
+  mpz_tdiv_q (mp1, mp2, mp3);
+  x = gmp_get_uint64 (mp1);
   mpz_clear (mp1);
   mpz_clear (mp2);
+  mpz_clear (mp3);
   return x;
 }