Browse Source

Math: add popcount().

pull/481/head
Vladimír Vondruš 6 years ago
parent
commit
9de4717f0e
  1. 1
      doc/changelog.dox
  2. 24
      src/Magnum/Math/Functions.cpp
  3. 30
      src/Magnum/Math/Functions.h
  4. 17
      src/Magnum/Math/Test/FunctionsTest.cpp

1
doc/changelog.dox

@ -70,6 +70,7 @@ See also:
- Added @ref Math::fmod() (see [mosra/magnum#454](https://github.com/mosra/magnum/pull/454))
- Added @ref Math::binomialCoefficient() (see [mosra/magnum#461](https://github.com/mosra/magnum/pull/461))
- Added @ref Math::popcount()
@subsubsection changelog-latest-new-meshtools MeshTools library

24
src/Magnum/Math/Functions.cpp

@ -30,6 +30,30 @@
namespace Magnum { namespace Math {
#if !defined(CORRADE_TARGET_GCC) && !defined(CORRADE_TARGET_CLANG)
namespace {
/* https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
there's also https://stackoverflow.com/a/109025 which mostly just copies
parts of this together with a lot of noise and syntax errors. */
template<class T> inline UnsignedInt popcountImplementation(T v) {
v = v - ((v >> 1) & ~T(0)/3);
v = (v & ~T(0)/15*3) + ((v >> 2) & ~T(0)/15*3);
v = (v + (v >> 4)) & ~T(0)/255*15;
return (v*(~T(0)/255)) >> (sizeof(T) - 1)*8;
}
}
UnsignedInt popcount(UnsignedInt number) {
return popcountImplementation(number);
}
UnsignedInt popcount(UnsignedLong number) {
return popcountImplementation(number);
}
#endif
UnsignedInt log(UnsignedInt base, UnsignedInt number) {
UnsignedInt log = 0;
while(number /= base)

30
src/Magnum/Math/Functions.h

@ -93,6 +93,36 @@ time, with @f$ n \ge k \ge 0 @f$: @f[
*/
UnsignedLong MAGNUM_EXPORT binomialCoefficient(UnsignedInt n, UnsignedInt k);
/**
@brief Count of bits set in a number
@m_since_latest
Expands to `__builtin_popcount` / `__builtin_popcountll` on GCC and Clang, uses
the [Counting bits set, in parallel](https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel)
implementation from Sean Eron Anderson Bit Twiddling Hacks page on MSVC and
elsewhere.
*/
/* Explicitly checking for Clang in addition to GCC to catch also clang-cl */
#if defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG)
inline UnsignedInt popcount(UnsignedInt number) {
return __builtin_popcount(number);
}
#else
MAGNUM_EXPORT UnsignedInt popcount(UnsignedInt number);
#endif
/**
@overload
@m_since_latest
*/
#if defined(CORRADE_TARGET_GCC) || defined(CORRADE_TARGET_CLANG)
inline UnsignedInt popcount(UnsignedLong number) {
return __builtin_popcountll(number);
}
#else
MAGNUM_EXPORT UnsignedInt popcount(UnsignedLong number);
#endif
/**
@{ @name Trigonometric functions

17
src/Magnum/Math/Test/FunctionsTest.cpp

@ -36,6 +36,8 @@ namespace Magnum { namespace Math { namespace Test { namespace {
struct FunctionsTest: Corrade::TestSuite::Tester {
explicit FunctionsTest();
template<class T> void popcount();
void powIntegral();
void pow();
@ -99,6 +101,10 @@ typedef Math::Vector3<Byte> Vector3b;
typedef Math::Vector3<Int> Vector3i;
FunctionsTest::FunctionsTest() {
addRepeatedTests<FunctionsTest>({
&FunctionsTest::popcount<UnsignedInt>,
&FunctionsTest::popcount<UnsignedLong>}, 8);
addTests({&FunctionsTest::powIntegral,
&FunctionsTest::pow,
@ -154,6 +160,17 @@ FunctionsTest::FunctionsTest() {
});
}
template<class T> void FunctionsTest::popcount() {
setTestCaseTemplateName(TypeTraits<T>::name());
/* Trivial cases */
CORRADE_COMPARE(Math::popcount(T(0)), 0);
CORRADE_COMPARE(Math::popcount(~T{}), sizeof(T)*8);
/* 0x101101011101000110010100 */
CORRADE_COMPARE(Math::popcount(T(0xb5d194) << testCaseRepeatId()), 12);
}
void FunctionsTest::powIntegral() {
CORRADE_COMPARE(Math::pow<10>(2ul), 1024ul);
CORRADE_COMPARE(Math::pow<0>(3ul), 1ul);

Loading…
Cancel
Save