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.
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);
} 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)
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;
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;
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;
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;
if (num == 0)
return 0;
+ if (num == 1 && denom == 1)
+ return val;
+
if (val <= G_MAXUINT32) {
/* simple case */
result.ll = val * num / denom;
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);