utils: improve gst_util_ceil_log2

According to the following comparison of algorithms, the value
for 0 and 1 was giving an incorrect result.

https://gist.github.com/ceyusa/6061b33ac109a68bcd222f6919968c9a

More information here:
https://github.com/rofrol/codeforces/blob/master/ceil_log2.c

Use a different algorithm which offers better result and keep the
performance.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7429>
This commit is contained in:
Stéphane Cerveau 2024-08-30 13:21:30 +02:00 committed by GStreamer Marge Bot
parent 65e071c1c8
commit a6f82ba590
3 changed files with 41 additions and 20 deletions

View file

@ -57259,7 +57259,7 @@ element or %NULL if nothing was found</doc>
</parameters>
</function>
<function name="util_ceil_log2" c:identifier="gst_util_ceil_log2" version="1.24">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">Return a max num of log2.</doc>
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">Returns smallest integral value not less than log2(v).</doc>
<source-position filename="../subprojects/gstreamer/gst/gstutils.h"/>
<return-value transfer-ownership="none">
<doc xml:space="preserve" filename="../subprojects/gstreamer/gst/gstutils.c">a computed #guint val.</doc>

View file

@ -4484,7 +4484,7 @@ gst_bit_storage_uint64 (guint64 in)
* gst_util_ceil_log2:
* @v: a #guint32 value.
*
* Return a max num of log2.
* Returns smallest integral value not less than log2(v).
*
* Returns: a computed #guint val.
*
@ -4493,25 +4493,29 @@ gst_bit_storage_uint64 (guint64 in)
guint
gst_util_ceil_log2 (guint32 v)
{
/* Compute Ceil(Log2(v)) */
/* Derived from branchless code for integer log2(v) from:
<http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog> */
guint r, shift;
static const unsigned int t[6] = {
0x00000000ull,
0xFFFF0000ull,
0x0000FF00ull,
0x000000F0ull,
0x0000000Cull,
0x000000002ull
};
v--;
r = (v > 0xFFFF) << 4;
v >>= r;
shift = (v > 0xFF) << 3;
v >>= shift;
r |= shift;
shift = (v > 0xF) << 2;
v >>= shift;
r |= shift;
shift = (v > 0x3) << 1;
v >>= shift;
r |= shift;
r |= (v >> 1);
return r + 1;
g_return_val_if_fail (v != 0, -1);
int y = (((v & (v - 1)) == 0) ? 0 : 1);
int j = 32;
int i;
for (i = 0; i < 6; i++) {
int k = (((v & t[i]) == 0) ? 0 : j);
y += k;
v >>= k;
j >>= 1;
}
return y;
}
/**

View file

@ -1990,6 +1990,21 @@ GST_START_TEST (test_regression)
GST_END_TEST;
// 10 Values
static const int ceil_log2_values[] = {
-1, 0, 1, 2, 2, 3, 3, 3, 3, 4
};
GST_START_TEST (test_ceil_log2)
{
int i;
for (i = 1; i < 10; i++) {
fail_unless_equals_int (gst_util_ceil_log2 (i), ceil_log2_values[i]);
}
}
GST_END_TEST;
GST_START_TEST (test_mark_as_plugin_api)
{
GstPluginAPIFlags api_flags;
@ -2053,6 +2068,8 @@ gst_utils_suite (void)
tcase_add_test (tc_chain, test_mark_as_plugin_api);
tcase_add_test (tc_chain, test_ceil_log2);
return s;
}