check/gst/gstutils.c: Updated check, add some scaling accuracy checking code.
authorWim Taymans <wim.taymans@gmail.com>
Mon, 28 Nov 2005 18:44:11 +0000 (18:44 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Mon, 28 Nov 2005 18:44:11 +0000 (18:44 +0000)
Original commit message from CVS:
* check/gst/gstutils.c: (GST_START_TEST):
Updated check, add some scaling accuracy checking code.

* gst/gstutils.c: (gst_util_div128_64),
(gst_util_uint64_scale_int64), (gst_util_uint64_scale),
(gst_util_uint64_scale_int):
Fix 6 times faster division code. Optimize for common
1/1 and less common X/1 cases.

ChangeLog
check/gst/gstutils.c
gst/gstutils.c
tests/check/gst/gstutils.c

index 3ca55b8..50e92cd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2005-11-28  Wim Taymans  <wim@fluendo.com>
 
+       * check/gst/gstutils.c: (GST_START_TEST):
+       Updated check, add some scaling accuracy checking code.
+
+       * gst/gstutils.c: (gst_util_div128_64),
+       (gst_util_uint64_scale_int64), (gst_util_uint64_scale),
+       (gst_util_uint64_scale_int):
+       Fix 6 times faster division code. Optimize for common 
+       1/1 and less common X/1 cases.
+
+2005-11-28  Wim Taymans  <wim@fluendo.com>
+
        * check/gst/gstutils.c: (GST_START_TEST), (gst_utils_suite):
        More checks.
 
index 00b48b0..2812420 100644 (file)
@@ -236,19 +236,35 @@ GST_START_TEST (test_math_scale_uint64)
 
 GST_START_TEST (test_math_scale_random)
 {
-  guint64 val, num, denom, res;;
+  guint64 val, num, denom, res;
   GRand *rand;
   gint i;
 
   rand = g_rand_new ();
 
-  i = 1000;
+  i = 1000000;
   while (i--) {
+    guint64 check, diff;
+
     val = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand);
     num = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand);
     denom = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand);
 
     res = gst_util_uint64_scale (val, num, denom);
+    check = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (val) *
+        gst_guint64_to_gdouble (num) / gst_guint64_to_gdouble (denom));
+
+    if (res < G_MAXUINT64 && check < G_MAXUINT64) {
+      if (res > check)
+        diff = res - check;
+      else
+        diff = check - res;
+
+      /* some arbitrary value, really.. someone do the proper math to get
+       * the upper bound */
+      if (diff > 20000)
+        fail_if (diff > 20000);
+    }
   }
   g_rand_free (rand);
 
index 2645873..80cf783 100644 (file)
@@ -356,36 +356,6 @@ typedef union
   } l;
 } GstUInt64;
 
-static guint64
-gst_util_div128_64_iterate (GstUInt64 c1, GstUInt64 c0, guint64 denom)
-{
-  gint i;
-  gint64 mask;
-  GstUInt64 a0;
-
-  /* full 128/64 case, very slow... */
-  /* quotient is c1, c0 */
-  a0.ll = 0;                    /* remainder a0 */
-
-  /* This can be done faster, inspiration in Hacker's Delight p152 */
-  for (i = 0; i < 128; i++) {
-    /* shift 192 bits remainder:quotient, we only need to
-     * check the top bit since denom is only 64 bits. */
-    /* sign extend top bit into mask */
-    mask = ((gint32) a0.l.high) >> 31;
-    mask |= (a0.ll = (a0.ll << 1) | (c1.l.high >> 31));
-    c1.ll = (c1.ll << 1) | (c0.l.high >> 31);
-    c0.ll <<= 1;
-
-    /* if remainder >= denom or top bit was set */
-    if (mask >= denom) {
-      a0.ll -= denom;
-      c0.ll += 1;
-    }
-  }
-  return c0.ll;
-}
-
 /* based on Hacker's Delight p152 */
 static guint64
 gst_util_div128_64 (GstUInt64 c1, GstUInt64 c0, guint64 denom)
@@ -409,10 +379,12 @@ gst_util_div128_64 (GstUInt64 c1, GstUInt64 c0, guint64 denom)
   s += (s >> 8);
   s = (s + (s >> 16)) & 0x3f;
 
-  /* normalize divisor and dividend */
-  v.ll <<= s;
-  c1.ll = (c1.ll << s) | ((c0.l.high >> (32 - s)) & (-s >> 31));
-  c0.ll <<= s;
+  if (s > 0) {
+    /* normalize divisor and dividend */
+    v.ll <<= s;
+    c1.ll = (c1.ll << s) | (c0.l.high >> (32 - s));
+    c0.ll <<= s;
+  }
 
   q1.ll = c1.ll / v.l.high;
   rhat.ll = c1.ll - q1.ll * v.l.high;
@@ -489,6 +461,11 @@ gst_util_uint64_scale_int64 (guint64 val, guint64 num, guint64 denom)
   if (c1.ll >= denom)
     goto overflow;
 
+  /* shortcut for division by 1, c1.ll should be 0 because of the
+   * overflow check above. */
+  if (denom == 1)
+    return c0.ll;
+
   /* and 128/64 bits division, result fits 64 bits */
   if (denom <= G_MAXUINT32) {
     guint32 den = (guint32) denom;
@@ -501,10 +478,7 @@ gst_util_uint64_scale_int64 (guint64 val, guint64 num, guint64 denom)
     result.l.high = c1.ll / den;
     result.l.low = c0.ll / den;
   } else {
-    if (TRUE)
-      result.ll = gst_util_div128_64_iterate (c1, c0, denom);
-    else
-      result.ll = gst_util_div128_64 (c1, c0, denom);
+    result.ll = gst_util_div128_64 (c1, c0, denom);
   }
   return result.ll;
 
@@ -534,6 +508,9 @@ gst_util_uint64_scale (guint64 val, guint64 num, guint64 denom)
   if (num == 0)
     return 0;
 
+  if (num == 1 && denom == 1)
+    return val;
+
   /* if the denom is high, we need to do a 64 muldiv */
   if (denom > G_MAXINT32)
     goto do_int64;
@@ -581,6 +558,9 @@ gst_util_uint64_scale_int (guint64 val, gint num, gint denom)
   if (num == 0)
     return 0;
 
+  if (num == 1 && denom == 1)
+    return val;
+
   if (val <= G_MAXUINT32) {
     /* simple case */
     result.ll = val * num / denom;
index 00b48b0..2812420 100644 (file)
@@ -236,19 +236,35 @@ GST_START_TEST (test_math_scale_uint64)
 
 GST_START_TEST (test_math_scale_random)
 {
-  guint64 val, num, denom, res;;
+  guint64 val, num, denom, res;
   GRand *rand;
   gint i;
 
   rand = g_rand_new ();
 
-  i = 1000;
+  i = 1000000;
   while (i--) {
+    guint64 check, diff;
+
     val = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand);
     num = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand);
     denom = ((guint64) g_rand_int (rand)) << 32 | g_rand_int (rand);
 
     res = gst_util_uint64_scale (val, num, denom);
+    check = gst_gdouble_to_guint64 (gst_guint64_to_gdouble (val) *
+        gst_guint64_to_gdouble (num) / gst_guint64_to_gdouble (denom));
+
+    if (res < G_MAXUINT64 && check < G_MAXUINT64) {
+      if (res > check)
+        diff = res - check;
+      else
+        diff = check - res;
+
+      /* some arbitrary value, really.. someone do the proper math to get
+       * the upper bound */
+      if (diff > 20000)
+        fail_if (diff > 20000);
+    }
   }
   g_rand_free (rand);