A follow-up from a discussion in !1080.
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2018,2019,2020 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
return static_cast<int>(rint(x));
}
+//! \brief Check whether \p v is an integer power of 2.
+template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
+#if defined(__NVCC__) && !defined(__CUDACC_RELAXED_CONSTEXPR__)
+/* In CUDA 11, a constexpr function cannot be called from a function with incompatible execution
+ * space, unless --expt-relaxed-constexpr flag is set */
+__host__ __device__
+#endif
+ static inline constexpr bool
+ isPowerOfTwo(const T v)
+{
+ return (v > 0) && ((v & (v - 1)) == 0);
+}
+
} // namespace gmx
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2016,2017,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2016,2017,2018,2019,2020 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
float& fy,
float& fz)
{
- if (!(order & (order - 1))) // Only for orders of power of 2
+ if (gmx::isPowerOfTwo(order)) // Only for orders of power of 2
{
const unsigned int activeMask = c_fullWarpMask;
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
* Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
template<unsigned int factor>
static size_t roundUpToMultipleOfFactor(size_t number)
{
- static_assert(factor > 0 && (factor & (factor - 1)) == 0,
- "factor should be >0 and a power of 2");
+ static_assert(gmx::isPowerOfTwo(factor));
/* We need to add a most factor-1 and because factor is a power of 2,
* we get the result by masking out the bits corresponding to factor-1.
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019 by the GROMACS development team.
+ * Copyright (c) 2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
}
}
+template<typename T>
+class FunctionTestIntegerTypes : public ::testing::Test
+{
+};
+
+typedef ::testing::Types<char, unsigned char, int, unsigned int, long, unsigned long> IntegerTypes;
+TYPED_TEST_CASE(FunctionTestIntegerTypes, IntegerTypes);
+
+TYPED_TEST(FunctionTestIntegerTypes, IsPowerOfTwo)
+{
+ if (std::is_signed_v<TypeParam>)
+ {
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(std::numeric_limits<TypeParam>::min()));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-16));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-3));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-2));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(-1));
+ }
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(0));
+ EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(1));
+ EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(2));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(3));
+ EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(4));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(5));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(6));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(24));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(63));
+ EXPECT_EQ(true, gmx::isPowerOfTwo<TypeParam>(64));
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(66));
+ // Max for any type is always 2^x - 1
+ EXPECT_EQ(false, gmx::isPowerOfTwo<TypeParam>(std::numeric_limits<TypeParam>::max()));
+}
+
} // namespace
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
#include "gromacs/gpu_utils/devicebuffer.cuh"
#include "gromacs/gpu_utils/gputraits.cuh"
#include "gromacs/gpu_utils/vectype_ops.cuh"
+#include "gromacs/math/functions.h"
#include "gromacs/math/vec.h"
#include "gromacs/mdlib/constr.h"
#include "gromacs/pbcutil/pbc.h"
static_assert(sizeof(real) == sizeof(float),
"Real numbers should be in single precision in GPU code.");
static_assert(
- c_threadsPerBlock > 0 && ((c_threadsPerBlock & (c_threadsPerBlock - 1)) == 0),
+ gmx::isPowerOfTwo(c_threadsPerBlock),
"Number of threads per block should be a power of two in order for reduction to work.");
allocateDeviceBuffer(&kernelParams_.d_virialScaled, 6, deviceContext_);
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
#include "gromacs/gpu_utils/devicebuffer.h"
#include "gromacs/gpu_utils/gputraits.cuh"
#include "gromacs/gpu_utils/vectype_ops.cuh"
+#include "gromacs/math/functions.h"
#include "gromacs/math/vec.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/pbcutil/pbc_aiuc_cuda.cuh"
static_assert(sizeof(real) == sizeof(float),
"Real numbers should be in single precision in GPU code.");
static_assert(
- c_threadsPerBlock > 0 && ((c_threadsPerBlock & (c_threadsPerBlock - 1)) == 0),
+ gmx::isPowerOfTwo(c_threadsPerBlock),
"Number of threads per block should be a power of two in order for reduction to work.");
// This is to prevent the assertion failure for the systems without water
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
* Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
* and including many others, as listed in the AUTHORS file in the
* top-level source directory and at http://www.gromacs.org.
// A fatal error is generated when this is not the case.
static void generateCoordinates(int multiplicationFactor, std::vector<gmx::RVec>* coordinates, matrix box)
{
- if (multiplicationFactor < 1 || (multiplicationFactor & (multiplicationFactor - 1)) != 0)
+ if (!gmx::isPowerOfTwo(multiplicationFactor))
{
gmx_fatal(FARGS, "The size factor has to be a power of 2");
}
*/
static inline int get_2log(int n)
{
- // TODO: Replace with gmx::Log2I?
- int log2 = 0;
- while ((1 << log2) < n)
- {
- log2++;
- }
- if ((1 << log2) != n)
+ if (!gmx::isPowerOfTwo(n))
{
gmx_fatal(FARGS, "nbnxn na_c (%d) is not a power of 2", n);
}
- return log2;
+ return gmx::log2I(n);
}
namespace Nbnxm