summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-02-25 15:25:08 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-02-26 16:10:14 -0700
commite0a04cbc3d159a84a1aa845743a0b89981e16224 (patch)
tree96f9555da40d9731d6aa96a7431db752b8d293d8
parent66efca9146357621118d565359b91326d1a96d0a (diff)
libmisc: macro.h: Add LM_FLOORLOG2
-rw-r--r--libmisc/include/libmisc/macro.h9
-rw-r--r--libmisc/tests/test_macro.c25
2 files changed, 29 insertions, 5 deletions
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h
index 149c4bb..b3e235c 100644
--- a/libmisc/include/libmisc/macro.h
+++ b/libmisc/include/libmisc/macro.h
@@ -17,10 +17,11 @@
/* numeric */
#define LM_ARRAY_LEN(ary) (sizeof(ary)/sizeof((ary)[0]))
-#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) )
-#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */
-#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */
-#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1)
+#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */
+#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */
+#define LM_ROUND_DOWN(n, d) ( ((n)/(d)) * (d) ) /** Return `n` rounded down to the nearest multiple of `d` */
+#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */
+#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */
/* strings */
diff --git a/libmisc/tests/test_macro.c b/libmisc/tests/test_macro.c
index 7cbf9d3..69655d1 100644
--- a/libmisc/tests/test_macro.c
+++ b/libmisc/tests/test_macro.c
@@ -1,6 +1,6 @@
/* libmisc/tests/test_macro.c - Tests for <libmisc/macro.h>
*
- * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com>
+ * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -9,6 +9,7 @@
#include "test.h"
int main() {
+ printf("== LM_NEXT_POWER_OF_2 =====================================\n");
/* valid down to 0. */
test_assert(LM_NEXT_POWER_OF_2(0) == 1);
test_assert(LM_NEXT_POWER_OF_2(1) == 2);
@@ -28,5 +29,27 @@ int main() {
/* Valid up to 0x8000000000000000-1 = (1<<63)-1 */
test_assert(LM_NEXT_POWER_OF_2(0x8000000000000000) == 0); /* :( */
+ printf("== LM_FLOORLOG2 ===========================================\n");
+ /* valid down to 1. */
+ test_assert(LM_FLOORLOG2(1) == 0);
+ test_assert(LM_FLOORLOG2(2) == 1);
+ test_assert(LM_FLOORLOG2(3) == 1);
+ test_assert(LM_FLOORLOG2(4) == 2);
+ test_assert(LM_FLOORLOG2(5) == 2);
+ test_assert(LM_FLOORLOG2(6) == 2);
+ test_assert(LM_FLOORLOG2(7) == 2);
+ test_assert(LM_FLOORLOG2(8) == 3);
+ /* ... */
+ test_assert(LM_FLOORLOG2(16) == 4);
+ /* ... */
+ test_assert(LM_FLOORLOG2(0x80000000) == 31);
+ /* ... */
+ test_assert(LM_FLOORLOG2(0xFFFFFFFF) == 31);
+ test_assert(LM_FLOORLOG2(0x100000000) == 32);
+ /* ... */
+ test_assert(LM_FLOORLOG2(0x8000000000000000) == 63);
+ /* ... */
+ test_assert(LM_FLOORLOG2(0xFFFFFFFFFFFFFFFF) == 63);
+
return 0;
}