Skip to content

Commit

Permalink
Merge pull request #157 from yosupo06/issue/153
Browse files Browse the repository at this point in the history
rename internal_bit functions to follow the cpp20 manner
  • Loading branch information
yosupo06 authored Mar 19, 2023
2 parents e1c0e55 + 67a9897 commit 47b2ec4
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 54 deletions.
16 changes: 8 additions & 8 deletions atcoder/convolution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ template <class mint,
int g = internal::primitive_root<mint::mod()>,
internal::is_static_modint_t<mint>* = 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<mint, rank2 + 1> root; // root[i]^(2^i) == 1
std::array<mint, rank2 + 1> iroot; // root[i] * iroot[i] == 1

Expand Down Expand Up @@ -60,7 +60,7 @@ struct fft_info {
template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly(std::vector<mint>& a) {
int n = int(a.size());
int h = internal::ceil_pow2(n);
int h = internal::countr_zero((unsigned int)n);

static const fft_info<mint> info;

Expand All @@ -78,7 +78,7 @@ void butterfly(std::vector<mint>& 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 {
Expand All @@ -104,7 +104,7 @@ void butterfly(std::vector<mint>& 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;
}
Expand All @@ -114,7 +114,7 @@ void butterfly(std::vector<mint>& a) {
template <class mint, internal::is_static_modint_t<mint>* = nullptr>
void butterfly_inv(std::vector<mint>& a) {
int n = int(a.size());
int h = internal::ceil_pow2(n);
int h = internal::countr_zero((unsigned int)n);

static const fft_info<mint> info;

Expand All @@ -135,7 +135,7 @@ void butterfly_inv(std::vector<mint>& a) {
;
}
if (s + 1 != (1 << (len - 1)))
irot *= info.irate2[bsf(~(unsigned int)(s))];
irot *= info.irate2[countr_zero(~(unsigned int)(s))];
}
len--;
} else {
Expand Down Expand Up @@ -167,7 +167,7 @@ void butterfly_inv(std::vector<mint>& 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;
}
Expand Down Expand Up @@ -198,7 +198,7 @@ std::vector<mint> convolution_naive(const std::vector<mint>& a,
template <class mint, internal::is_static_modint_t<mint>* = nullptr>
std::vector<mint> convolution_fft(std::vector<mint> a, std::vector<mint> 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);
Expand Down
39 changes: 25 additions & 14 deletions atcoder/internal_bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,32 @@
#include <intrin.h>
#endif

#if __cplusplus >= 202002L
#include <bit>
#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);
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions atcoder/lazysegtree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ struct lazy_segtree {
lazy_segtree() : lazy_segtree(0) {}
explicit lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
explicit lazy_segtree(const std::vector<S>& 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<S>(2 * size, e());
lz = std::vector<F>(size, id());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
Expand Down
4 changes: 2 additions & 2 deletions atcoder/segtree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ template <class S, S (*op)(S, S), S (*e)()> struct segtree {
segtree() : segtree(0) {}
explicit segtree(int n) : segtree(std::vector<S>(n, e())) {}
explicit segtree(const std::vector<S>& 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<S>(2 * size, e());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
for (int i = size - 1; i >= 1; i--) {
Expand Down
74 changes: 46 additions & 28 deletions test/unittest/bit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>::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<unsigned int>::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<unsigned int>::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<unsigned int>::max()));
}

0 comments on commit 47b2ec4

Please sign in to comment.