diff --git a/atcoder/convolution.hpp b/atcoder/convolution.hpp index 280ccc5..7b27f81 100644 --- a/atcoder/convolution.hpp +++ b/atcoder/convolution.hpp @@ -18,7 +18,7 @@ template , internal::is_static_modint_t* = nullptr> struct fft_info { - static constexpr int rank2 = bsf_constexpr(mint::mod() - 1); + static constexpr int rank2 = countr_zero_constexpr(mint::mod() - 1); std::array root; // root[i]^(2^i) == 1 std::array iroot; // root[i] * iroot[i] == 1 @@ -60,7 +60,7 @@ struct fft_info { template * = nullptr> void butterfly(std::vector& a) { int n = int(a.size()); - int h = internal::ceil_pow2(n); + int h = internal::countr_zero((unsigned int)n); static const fft_info info; @@ -78,7 +78,7 @@ void butterfly(std::vector& a) { a[i + offset + p] = l - r; } if (s + 1 != (1 << len)) - rot *= info.rate2[bsf(~(unsigned int)(s))]; + rot *= info.rate2[countr_zero(~(unsigned int)(s))]; } len++; } else { @@ -104,7 +104,7 @@ void butterfly(std::vector& a) { a[i + offset + 3 * p] = a0 + na2 + (mod2 - a1na3imag); } if (s + 1 != (1 << len)) - rot *= info.rate3[bsf(~(unsigned int)(s))]; + rot *= info.rate3[countr_zero(~(unsigned int)(s))]; } len += 2; } @@ -114,7 +114,7 @@ void butterfly(std::vector& a) { template * = nullptr> void butterfly_inv(std::vector& a) { int n = int(a.size()); - int h = internal::ceil_pow2(n); + int h = internal::countr_zero((unsigned int)n); static const fft_info info; @@ -135,7 +135,7 @@ void butterfly_inv(std::vector& a) { ; } if (s + 1 != (1 << (len - 1))) - irot *= info.irate2[bsf(~(unsigned int)(s))]; + irot *= info.irate2[countr_zero(~(unsigned int)(s))]; } len--; } else { @@ -167,7 +167,7 @@ void butterfly_inv(std::vector& a) { irot3.val(); } if (s + 1 != (1 << (len - 2))) - irot *= info.irate3[bsf(~(unsigned int)(s))]; + irot *= info.irate3[countr_zero(~(unsigned int)(s))]; } len -= 2; } @@ -198,7 +198,7 @@ std::vector convolution_naive(const std::vector& a, template * = nullptr> std::vector convolution_fft(std::vector a, std::vector b) { int n = int(a.size()), m = int(b.size()); - int z = 1 << internal::ceil_pow2(n + m - 1); + int z = (int)internal::bit_ceil((unsigned int)(n + m - 1)); assert(mint::mod() % z == 1); a.resize(z); internal::butterfly(a); diff --git a/atcoder/internal_bit.hpp b/atcoder/internal_bit.hpp index ada311a..3b2126d 100644 --- a/atcoder/internal_bit.hpp +++ b/atcoder/internal_bit.hpp @@ -5,29 +5,32 @@ #include #endif +#if __cplusplus >= 202002L +#include +#endif + namespace atcoder { namespace internal { -// @param n `0 <= n` -// @return minimum non-negative `x` s.t. `n <= 2**x` -int ceil_pow2(int n) { - int x = 0; - while ((1U << x) < (unsigned int)(n)) x++; - return x; -} +#if __cplusplus >= 202002L -// @param n `1 <= n` -// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0` -constexpr int bsf_constexpr(unsigned int n) { - int x = 0; - while (!(n & (1 << x))) x++; +using std::bit_ceil; + +#else + +// @return same with std::bit::bit_ceil +unsigned int bit_ceil(unsigned int n) { + unsigned int x = 1; + while (x < (unsigned int)(n)) x *= 2; return x; } +#endif + // @param n `1 <= n` -// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0` -int bsf(unsigned int n) { +// @return same with std::bit::countr_zero +int countr_zero(unsigned int n) { #ifdef _MSC_VER unsigned long index; _BitScanForward(&index, n); @@ -37,6 +40,14 @@ int bsf(unsigned int n) { #endif } +// @param n `1 <= n` +// @return same with std::bit::countr_zero +constexpr int countr_zero_constexpr(unsigned int n) { + int x = 0; + while (!(n & (1 << x))) x++; + return x; +} + } // namespace internal } // namespace atcoder diff --git a/atcoder/lazysegtree.hpp b/atcoder/lazysegtree.hpp index f4c5e4f..2119d82 100644 --- a/atcoder/lazysegtree.hpp +++ b/atcoder/lazysegtree.hpp @@ -22,8 +22,8 @@ struct lazy_segtree { lazy_segtree() : lazy_segtree(0) {} explicit lazy_segtree(int n) : lazy_segtree(std::vector(n, e())) {} explicit lazy_segtree(const std::vector& v) : _n(int(v.size())) { - log = internal::ceil_pow2(_n); - size = 1 << log; + size = (int)internal::bit_ceil((unsigned int)(_n)); + log = internal::countr_zero((unsigned int)size); d = std::vector(2 * size, e()); lz = std::vector(size, id()); for (int i = 0; i < _n; i++) d[size + i] = v[i]; diff --git a/atcoder/segtree.hpp b/atcoder/segtree.hpp index d07018b..c8bfef6 100644 --- a/atcoder/segtree.hpp +++ b/atcoder/segtree.hpp @@ -14,8 +14,8 @@ template struct segtree { segtree() : segtree(0) {} explicit segtree(int n) : segtree(std::vector(n, e())) {} explicit segtree(const std::vector& v) : _n(int(v.size())) { - log = internal::ceil_pow2(_n); - size = 1 << log; + size = (int)internal::bit_ceil((unsigned int)(_n)); + log = internal::countr_zero((unsigned int)size); d = std::vector(2 * size, e()); for (int i = 0; i < _n; i++) d[size + i] = v[i]; for (int i = size - 1; i >= 1; i--) { diff --git a/test/unittest/bit_test.cpp b/test/unittest/bit_test.cpp index 18e38f4..0de6918 100644 --- a/test/unittest/bit_test.cpp +++ b/test/unittest/bit_test.cpp @@ -8,34 +8,52 @@ using namespace atcoder; using ll = long long; using ull = unsigned long long; -TEST(BitTest, CeilPow2) { - ASSERT_EQ(0, internal::ceil_pow2(0)); - ASSERT_EQ(0, internal::ceil_pow2(1)); - ASSERT_EQ(1, internal::ceil_pow2(2)); - ASSERT_EQ(2, internal::ceil_pow2(3)); - ASSERT_EQ(2, internal::ceil_pow2(4)); - ASSERT_EQ(3, internal::ceil_pow2(5)); - ASSERT_EQ(3, internal::ceil_pow2(6)); - ASSERT_EQ(3, internal::ceil_pow2(7)); - ASSERT_EQ(3, internal::ceil_pow2(8)); - ASSERT_EQ(4, internal::ceil_pow2(9)); - ASSERT_EQ(30, internal::ceil_pow2(1 << 30)); - ASSERT_EQ(31, internal::ceil_pow2((1 << 30) + 1)); - ASSERT_EQ(31, internal::ceil_pow2(std::numeric_limits::max())); +TEST(BitTest, BitCeil) { + ASSERT_EQ(1, internal::bit_ceil(0U)); + ASSERT_EQ(1, internal::bit_ceil(1U)); + ASSERT_EQ(2, internal::bit_ceil(2U)); + ASSERT_EQ(4, internal::bit_ceil(3U)); + ASSERT_EQ(4, internal::bit_ceil(4U)); + ASSERT_EQ(8, internal::bit_ceil(5U)); + ASSERT_EQ(8, internal::bit_ceil(6U)); + ASSERT_EQ(8, internal::bit_ceil(7U)); + ASSERT_EQ(8, internal::bit_ceil(8U)); + ASSERT_EQ(16, internal::bit_ceil(9U)); + ASSERT_EQ(1U << 30, internal::bit_ceil(1U << 30)); + ASSERT_EQ(1U << 31, internal::bit_ceil((1U << 30) + 1)); + ASSERT_EQ(1U << 31, internal::bit_ceil((1U << 31) - 1)); + ASSERT_EQ(1U << 31, internal::bit_ceil(1U << 31)); } -TEST(BitTest, BSF) { - ASSERT_EQ(0, internal::bsf(1)); - ASSERT_EQ(1, internal::bsf(2)); - ASSERT_EQ(0, internal::bsf(3)); - ASSERT_EQ(2, internal::bsf(4)); - ASSERT_EQ(0, internal::bsf(5)); - ASSERT_EQ(1, internal::bsf(6)); - ASSERT_EQ(0, internal::bsf(7)); - ASSERT_EQ(3, internal::bsf(8)); - ASSERT_EQ(0, internal::bsf(9)); - ASSERT_EQ(30, internal::bsf(1U << 30)); - ASSERT_EQ(0, internal::bsf((1U << 31) - 1)); - ASSERT_EQ(31, internal::bsf(1U << 31)); - ASSERT_EQ(0, internal::bsf(std::numeric_limits::max())); +TEST(BitTest, CountrZero) { + ASSERT_EQ(0, internal::countr_zero(1U)); + ASSERT_EQ(1, internal::countr_zero(2U)); + ASSERT_EQ(0, internal::countr_zero(3U)); + ASSERT_EQ(2, internal::countr_zero(4U)); + ASSERT_EQ(0, internal::countr_zero(5U)); + ASSERT_EQ(1, internal::countr_zero(6U)); + ASSERT_EQ(0, internal::countr_zero(7U)); + ASSERT_EQ(3, internal::countr_zero(8U)); + ASSERT_EQ(0, internal::countr_zero(9U)); + ASSERT_EQ(30, internal::countr_zero(1U << 30)); + ASSERT_EQ(0, internal::countr_zero((1U << 31) - 1)); + ASSERT_EQ(31, internal::countr_zero(1U << 31)); + ASSERT_EQ(0, internal::countr_zero(std::numeric_limits::max())); +} + +TEST(BitTest, CountrZeroConstexpr) { + ASSERT_EQ(0, internal::countr_zero_constexpr(1U)); + ASSERT_EQ(1, internal::countr_zero_constexpr(2U)); + ASSERT_EQ(0, internal::countr_zero_constexpr(3U)); + ASSERT_EQ(2, internal::countr_zero_constexpr(4U)); + ASSERT_EQ(0, internal::countr_zero_constexpr(5U)); + ASSERT_EQ(1, internal::countr_zero_constexpr(6U)); + ASSERT_EQ(0, internal::countr_zero_constexpr(7U)); + ASSERT_EQ(3, internal::countr_zero_constexpr(8U)); + ASSERT_EQ(0, internal::countr_zero_constexpr(9U)); + ASSERT_EQ(30, internal::countr_zero_constexpr(1U << 30)); + ASSERT_EQ(0, internal::countr_zero_constexpr((1U << 31) - 1)); + ASSERT_EQ(31, internal::countr_zero_constexpr(1U << 31)); + ASSERT_EQ(0, + internal::countr_zero_constexpr(std::numeric_limits::max())); }