From cfaf158ebcb68cdc54b039100aa2f7be36e471fc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Jan 2022 13:47:14 +0900 Subject: [PATCH] [math] Add some bit-op functions Just 32-bit rounding to next higher power of two, and base 2 logarithm. Most importantly, they are suitable for use in initializers as they are constant in, constant out. --- include/QF/Makemodule.am | 1 + include/QF/math/bitop.h | 73 ++++++++++++++++++++++++++++++++++++ libs/util/test/Makemodule.am | 5 +++ libs/util/test/test-bitop.c | 55 +++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 include/QF/math/bitop.h create mode 100644 libs/util/test/test-bitop.c diff --git a/include/QF/Makemodule.am b/include/QF/Makemodule.am index 3892a430e..d36dd7ead 100644 --- a/include/QF/Makemodule.am +++ b/include/QF/Makemodule.am @@ -115,6 +115,7 @@ include_qf_input = \ include/QF/input/imt.h include_qf_math = \ + include/QF/math/bitop.h \ include/QF/math/dual.h \ include/QF/math/half.h \ include/QF/math/matrix3.h \ diff --git a/include/QF/math/bitop.h b/include/QF/math/bitop.h new file mode 100644 index 000000000..ee00ac6ca --- /dev/null +++ b/include/QF/math/bitop.h @@ -0,0 +1,73 @@ +/* + bitop.h + + bit-op functions + + Copyright (C) 2022 Bill Currie + + Author: Bill Currie + Date: 2022/1/23 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_math_bitop_h +#define __QF_math_bitop_h + +/** \defgroup mathlib_bitop Bit-op functions + \ingroup utils +*/ +///@{ + +#include "QF/qtypes.h" + +#define BITOP_RUP1__(x) ( (x) | ( (x) >> 1)) +#define BITOP_RUP2__(x) (BITOP_RUP1__(x) | (BITOP_RUP1__(x) >> 2)) +#define BITOP_RUP4__(x) (BITOP_RUP2__(x) | (BITOP_RUP2__(x) >> 4)) +#define BITOP_RUP8__(x) (BITOP_RUP4__(x) | (BITOP_RUP4__(x) >> 8)) +#define BITOP_RUP16__(x) (BITOP_RUP8__(x) | (BITOP_RUP8__(x) >> 16)) +/** Round x up to the next power of two. + + Rounds x up to the next power of two leaving exact powers of two + untouched. + + \param x The value to round + \return The next higher power of two or x if it already is a power + of two. +*/ +#define BITOP_RUP(x) (BITOP_RUP16__((uint32_t)(x) - 1) + 1) + +#define BITOP_LOG2__(x) (((((x) & 0xffff0000) != 0) << 4) \ + |((((x) & 0xff00ff00) != 0) << 3) \ + |((((x) & 0xf0f0f0f0) != 0) << 2) \ + |((((x) & 0xcccccccc) != 0) << 1) \ + |((((x) & 0xaaaaaaaa) != 0) << 0)) +/** Log base 2 rounded up. + + Finds the base 2 logarithm of x rounded up (ceil(log2(x))). + + \param x The value for which to find the base 2 logarithm. + \return Log base 2 of x, rounded up (2 -> 1, 3 -> 2, 4 -> 2) +*/ +#define BITOP_LOG2(x) BITOP_LOG2__(BITOP_RUP(x)) + +///@} + +#endif // __QF_math_bitop_h diff --git a/libs/util/test/Makemodule.am b/libs/util/test/Makemodule.am index 188239e11..7fa5a5f98 100644 --- a/libs/util/test/Makemodule.am +++ b/libs/util/test/Makemodule.am @@ -1,6 +1,7 @@ libs_util_tests = \ libs/util/test/test-bary \ libs/util/test/test-baryvf \ + libs/util/test/test-bitop \ libs/util/test/test-bsearch \ libs/util/test/test-cexpr \ libs/util/test/test-cmem \ @@ -36,6 +37,10 @@ libs_util_test_test_baryvf_SOURCES=libs/util/test/test-baryvf.c libs_util_test_test_baryvf_LDADD=libs/util/libQFutil.la libs_util_test_test_baryvf_DEPENDENCIES=libs/util/libQFutil.la +libs_util_test_test_bitop_SOURCES=libs/util/test/test-bitop.c +libs_util_test_test_bitop_LDADD=libs/util/libQFutil.la +libs_util_test_test_bitop_DEPENDENCIES=libs/util/libQFutil.la + libs_util_test_test_bsearch_SOURCES=libs/util/test/test-bsearch.c libs_util_test_test_bsearch_LDADD=libs/util/libQFutil.la libs_util_test_test_bsearch_DEPENDENCIES=libs/util/libQFutil.la diff --git a/libs/util/test/test-bitop.c b/libs/util/test/test-bitop.c new file mode 100644 index 000000000..795d023f5 --- /dev/null +++ b/libs/util/test/test-bitop.c @@ -0,0 +1,55 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "QF/math/bitop.h" + +struct { + uint32_t value; + uint32_t expect; +} tests [] = { + {BITOP_RUP(1), 1}, + {BITOP_RUP(2), 2}, + {BITOP_RUP(3), 4}, + {BITOP_RUP(4), 4}, + {BITOP_RUP(5), 8}, + {BITOP_RUP(7), 8}, + {BITOP_RUP(8), 8}, + {BITOP_RUP(0x40000000), 0x40000000}, + {BITOP_RUP(0x40000001), 0x80000000}, + {BITOP_LOG2(1), 0}, + {BITOP_LOG2(2), 1}, + {BITOP_LOG2(3), 2}, + {BITOP_LOG2(4), 2}, + {BITOP_LOG2(5), 3}, + {BITOP_LOG2(7), 3}, + {BITOP_LOG2(8), 3}, + {BITOP_LOG2(9), 4}, + {BITOP_LOG2(15), 4}, + {BITOP_LOG2(16), 4}, + {BITOP_LOG2(17), 5}, + {BITOP_LOG2(31), 5}, + {BITOP_LOG2(32), 5}, + {BITOP_LOG2(33), 6}, + {BITOP_LOG2(0x40000000), 30}, + {BITOP_LOG2(0x40000001), 31}, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) + +int +main (int argc, const char **argv) +{ + size_t i; + int res = 0; + + for (i = 0; i < num_tests; i++) { + if (tests[i].value != tests[i].expect) { + res |= 1; + printf ("test %d failed\n", (int) i); + printf ("expect: %8x\n", tests[i].expect); + printf ("got : %8x\n", tests[i].value); + } + } + return res; +}