获得C++的最低设置的最快方法是什么。 std :: bitset?

发布于 2025-01-26 12:53:11 字数 512 浏览 4 评论 0原文

我注意到 std :: bitset 没有用于返回或弹出的函数位置的最低集合(也不是最高的集合位)。什么是完成此任务的最快方法,特别是对于STD :: BITSET对象,不能保证为一定数量的位长吗?我在G ++编译器扩展程序中查看, c ++ 20 numerics numerics 找到与我的问题有关的任何东西。

要考虑的两种明显的方法将是在比特斯的长度上循环循环,并使用operator []或使用operator>>>逐渐移动位置直至第一个集合位置为成立。

I noticed that std::bitset does not have a function for returning or popping the lowest set bit of a bitset (nor the highest set bit for that matter). What is the fastest way to accomplish this task, specifically for std::bitset objects not guaranteed to be a certain number of bits long? I looked in the g++ compiler extensions and C++20 numerics library and didn't find anything related to my problem.

Two obvious methods to consider would be looping over the length of the bitset and using the operator[] or gradually shifting the bitset using operator>> until the first set bit is found.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

纵情客 2025-02-02 12:53:11

像大多数现代实现一样,我将使用尾随零,以使其易于处理没有设置的情况。要利用硬件计数落后指令,我们可以使用to_ullong(),但是要使它起作用,我们需要掩盖该值以使其适合无符号>未签名的长长

#include <bitset>
#include <bit>
#include <climits>

template<size_t N>
size_t count_trailingzero(std::bitset<N> b)
{
    if (b.none())
        return N;                   // The whole bitset was zero

    const decltype(b) mask(-1ULL);  // Mask to get the lowest unsigned long long
    size_t tz = 0;                  // The number of trailing zero bits
    const int width = sizeof(unsigned long long)*CHAR_BIT;
    do {
        auto lsw = (b & mask).to_ullong();  // The least significant word
        auto lsb = std::countr_zero(lsw);   // Position of the least significant bit

        if (lsb < width)                    // Found the first set bit from right
            return tz + lsb;
        
        // A set bit was not found because the lsw is all zero
        // so we'll increase the number of trailing zero bits
        tz += width;

        // Shift the bitset to get the next higher significant word
        b >>= width;
    } while (b.any());

    return tz;
}

Demo on Godbolt< /a>

以这种方式,不需要对单个位进行循环,并且可以使用硬件加速度。但这仍然不是最有效的方法,因为每次迭代仍然需要掩盖整个bitset。这就是为什么std :: bitset不是一般操作的好工具,而我总是在实践中避免使用它们。将阵列包装钻头操作的课程在性能和灵活性方面会更好

I'm going to use trailing zero like most modern implementations to make it easy to deal with the case where there's no set bit. To utilize the hardware count trailing zero instruction we can use to_ullong(), but to make it work we'll need to mask the value to make it fit in an unsigned long long

#include <bitset>
#include <bit>
#include <climits>

template<size_t N>
size_t count_trailingzero(std::bitset<N> b)
{
    if (b.none())
        return N;                   // The whole bitset was zero

    const decltype(b) mask(-1ULL);  // Mask to get the lowest unsigned long long
    size_t tz = 0;                  // The number of trailing zero bits
    const int width = sizeof(unsigned long long)*CHAR_BIT;
    do {
        auto lsw = (b & mask).to_ullong();  // The least significant word
        auto lsb = std::countr_zero(lsw);   // Position of the least significant bit

        if (lsb < width)                    // Found the first set bit from right
            return tz + lsb;
        
        // A set bit was not found because the lsw is all zero
        // so we'll increase the number of trailing zero bits
        tz += width;

        // Shift the bitset to get the next higher significant word
        b >>= width;
    } while (b.any());

    return tz;
}

Demo on Godbolt

This way no looping over individual bits is required and hardware acceleration can be used. But it's still not the most efficient method because each iteration the whole bitset still needs to be masked off. That's why std::bitset isn't a good tool for operating on bits in general and I always avoid them in practice. A class wrapping an array for bit operations will be much better in performance and flexibility

樱花坊 2025-02-02 12:53:11

没有.lsb().msb()成员函数,但是std :: bitset确实提供.size()在“> @phuctv 用于.yany() .count()),您可以在其中构造LSB和MSB例程。

假设有效的std :: bitset您可以使用.yany()()(或仅检查未符号值),验证至少一个位是TRUE设置的。验证至少一个位是正确的,只需从bit-0循环到bit-(bitset.size() - 1)使用检查设置位.test()获得LSB。然后,只需在相同的测试中反向循环以找到MSB。

简短的实现将是:

#include <iostream>
#include <bitset>

int main () {
  
  size_t i = 0;                 /* bit indiex */
  std::bitset<8> bits (236);    /* bitset '11101100' */
  
  if (!bits.any()) {  /* validate at least 1 bit set */
    std::cerr << "pop count is zero.\n";
    return 1;
  }
  
  /* loop bit 0 to bits.size() - 1 for LSB */
  do {
    if (bits.test(i))             /* test if bit set */
      break;
  } while (++i < bits.size());
  
  std::cout << "lsb in '" << bits << "' is: " << i << '\n';
  
  /* loop bit bits.size() - 1 to 0 for MSB */
  i = bits.size();
  while (i--) {
    if (bits.test(i))             /* test if bit set */
      break;
  }
  
  std::cout << "msb in '" << bits << "' is: " << i << '\n';
}

示例使用/输出

$ ./bin//bitset_test
lsb in '11101100' is: 2
msb in '11101100' is: 7

扩展了std :: bitset并添加.lsb() and .msb()成员函数

除了简单地编写几个功能外,您还可以从std :: bitset添加.lsb()。 MSB()成员函数到派生类。

使用以上相同实现的简短类声明可能是:

template<size_t Nb>
class mybitset : public std::bitset<Nb> {
  
  std::bitset<Nb> bits;
  
 public:
  mybitset (const std::bitset<Nb>&b) : std::bitset<Nb>{b} { bits = b; }
  
  size_t lsb();     /* extend std::bitset with .lsb() and .msb() members */
  size_t msb();
  
  template<size_t NB>
  friend std::ostream& operator << (std::ostream& os, const mybitset<NB>& b);
};

然后您可以直接使用.lsb().msb()成员,例如

int main () {
  
  mybitset<8> bits (236);       /* derived class */
  
  if (!bits.any()) {  /* validate at least one bit set */
    std::cerr << "bitset value is zero -- zero pop count.\n";
    return 1;
  }
  
  /* output LSB and MSB */
  std::cout << "lsb in '" << bits << "' is: " << bits.lsb() <<
             "\nmsb in '" << bits << "' is: " << bits.msb() << '\n';
}

(相同的输出)

There is no .lsb() or .msb() member functions, but std::bitset does provide .size() and .test() (and .any(), credit to @phuctv for use of .any() over .count()) with which you can construct the lsb and msb routines.

Presuming a valid std::bitset you can verify that at least one bit is set true using .any() (or just check the unsigned value). After verifying at least one bit is true, simply loop from bit-0 to bit-(bitset.size() - 1) checking for a set bit with .test() to obtain the LSB. Then just loop in reverse with the same test to find the MSB.

A short implementation would be:

#include <iostream>
#include <bitset>

int main () {
  
  size_t i = 0;                 /* bit indiex */
  std::bitset<8> bits (236);    /* bitset '11101100' */
  
  if (!bits.any()) {  /* validate at least 1 bit set */
    std::cerr << "pop count is zero.\n";
    return 1;
  }
  
  /* loop bit 0 to bits.size() - 1 for LSB */
  do {
    if (bits.test(i))             /* test if bit set */
      break;
  } while (++i < bits.size());
  
  std::cout << "lsb in '" << bits << "' is: " << i << '\n';
  
  /* loop bit bits.size() - 1 to 0 for MSB */
  i = bits.size();
  while (i--) {
    if (bits.test(i))             /* test if bit set */
      break;
  }
  
  std::cout << "msb in '" << bits << "' is: " << i << '\n';
}

Example Use/Output

$ ./bin//bitset_test
lsb in '11101100' is: 2
msb in '11101100' is: 7

Extend std::bitset and Add .lsb() and .msb() Member Functions

In addition to simply writing a couple of functions, you can just derive from std::bitset and add .lsb() and .msb() member functions to the derived class.

A short class declaration using the same implementations above could be:

template<size_t Nb>
class mybitset : public std::bitset<Nb> {
  
  std::bitset<Nb> bits;
  
 public:
  mybitset (const std::bitset<Nb>&b) : std::bitset<Nb>{b} { bits = b; }
  
  size_t lsb();     /* extend std::bitset with .lsb() and .msb() members */
  size_t msb();
  
  template<size_t NB>
  friend std::ostream& operator << (std::ostream& os, const mybitset<NB>& b);
};

Then you can simply use the .lsb() and .msb() members directly, e.g.

int main () {
  
  mybitset<8> bits (236);       /* derived class */
  
  if (!bits.any()) {  /* validate at least one bit set */
    std::cerr << "bitset value is zero -- zero pop count.\n";
    return 1;
  }
  
  /* output LSB and MSB */
  std::cout << "lsb in '" << bits << "' is: " << bits.lsb() <<
             "\nmsb in '" << bits << "' is: " << bits.msb() << '\n';
}

(same output)

海未深 2025-02-02 12:53:11

有点较晚的答案,C ++ 20包括 &lt; /代码>具有您想要的功能。

特别是 std :: countr_zero 连续0位的数量从最小显着的位开始。

#include <bit>
#include <iostream>

// This requires C++20 (or later)

int main() {
  std::cout << "lsb of 0b0100u is " << std::countr_zero(0b0100u) << "\n";
}

// std::countr_zero(0b0100u) is 2.

A bit of a late answer, C++20 includes <bit> which has the functions you want.

In particular std::countr_zero which returns the number of consecutive 0 bits starting from the least significant bit.

#include <bit>
#include <iostream>

// This requires C++20 (or later)

int main() {
  std::cout << "lsb of 0b0100u is " << std::countr_zero(0b0100u) << "\n";
}

// std::countr_zero(0b0100u) is 2.
后知后觉 2025-02-02 12:53:11

您可以做这样的事情:

#include <bitset>
#include <iostream>
int main(int argc, char **argv) {
  std::bitset<32> your_bit{0B1010000};
  int lsb = your_bit[0];
  std::cout << lsb << '\n';
}

You can do something like this:

#include <bitset>
#include <iostream>
int main(int argc, char **argv) {
  std::bitset<32> your_bit{0B1010000};
  int lsb = your_bit[0];
  std::cout << lsb << '\n';
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文