【问题标题】:Bitset, vector of bool or vector of ints for simple big integer位集,布尔向量或整数向量,用于简单的大整数
【发布时间】:2018-03-02 02:26:38
【问题描述】:

我有一个算法,我目前使用两个无符号整数作为位图来存储有关输入的信息;这将最大输入大小限制为 64,因此我想创建一个版本,其中整数被替换为位集或简单的大整数。我开始使用vector 写一些东西,但是环顾四周,我看到很多答案告诉我要避免使用vector

我需要的操作:

  • 初始化为全零。
  • 左移(乘以 2)并设置新的 lsb。
  • 添加和设置 msb。
  • 比较两个集合以首先找到最小/字典顺序。

创建它们时,我知道最大位数,但起初我只需要 1 位;然后,在每一步,一组左移,而另一组将添加一个新的最高位:

{
    a <<= 1;
    a[0] = x;
    b[++msb] = y;
    if (a < b) b = a;
} 

如果我创建大小为 1 的位集,然后逐渐扩展它们,那么比较可能会比我立即将长度设置为最大值并可能有数千个前导零更快?

那么我应该继续使用vector 还是使用std::bitset(不幸的是它是固定大小的)或者编写一个简单的biginteger 实现,该实现能够使用无符号整数向量完成上述操作?


使用vector可以初始化长度为零的向量:

std::vector<bool> a(0), b(0);

然后像这样执行上面提到的操作:

{
    a.push_back(x);
    b.insert(b.begin(), y);
    if (a < b) b = a;
}

【问题讨论】:

  • 我不确定您提到的任何容器是否支持您想要的全套操作,但那又如何?您可以使用标准容器之一来实现您自己的类(就像其他人建议的那样,我会避免使用vector &lt;bool&gt;),然后根据情况更改实现。这难道不是面向对象编程应该做的事情之一吗?
  • 也许你应该看看GMP
  • vector&lt;bool&gt;的批评通常是它没有存储任何bools。这使得不可能满足容器的所有要求,尤其是返回引用为bool&amp;。如果这对您来说不是问题,那么该类型就没有什么特别的问题了。

标签: c++ vector biginteger bitset std-bitset


【解决方案1】:

我认为boost::dynamic_bitset 是你所追求的。

这是一个满足您要求的示例:

#include <iostream>
#include <boost/dynamic_bitset.hpp>
int main() {
    boost::dynamic_bitset<> a(3, 2); // a = 010
    a[0] = true;                     // a = 011
    a.push_back(true);               // a = 1011
    boost::dynamic_bitset<> b = a;   // b = 1011
    a <<= 1;                         // a = 0110
    bool aless = a < b;              // true
    unsigned long al = a.to_ulong(); // al = 6
    std::cout << "a=" << a << ", al=" << a.to_ulong() << "\n"
              << "b=" << b << ", bl=" << b.to_ulong() << "\n"
              << "a<b=" << (a<b) << "\n";
}

几点说明:

  • 该对象是完全动态的,没有机会利用您对最大尺寸的了解。我相信它甚至不使用小对象优化,所以它总是会分配一些动态内存。
  • 构造函数有点奇怪。第一个参数是位数,第二个参数是它们的整数值。这意味着按照您的要求初始化为单个真位,您将使用dynamic_bitset&lt;&gt;(1, 1)。遗憾的是没有initializer_list 构造函数,所以你不能只做a = {true}。也许最清楚的事情是默认构造对象和 push_back(true) 在单独的行上。
  • push_back 影响最高有效位,即左侧的值。这是因为“front”表示元素 0,它是最低有效位。
  • 左移运算符不会增大对象,因此要将项目附加到前面,您需要:
    1. a.push_back(false)(你推送的值无关紧要,因为它会被扔掉)。
    2. a &lt;&lt;= 1
    3. a[0] = x 如果要设置新值。
  • to_ulong() 仅在对象具有足够少的元素以适合您平台上的 unsigned long 时才有效。请注意,它不是unsigned long long,因此即使在 64 位系统上,它也可能是 32 位。
  • 还有一些其他有趣的方法值得一看,例如any()all()count()

【讨论】:

  • 您能否详细说明并提供客观论据,或者这只是一个意见?
  • 恐怕这只是一个意见。我对动态位集的经验是界面相当面向位集。你懂的。如“位集”(不是:多肢整数类型)/cc @Christophe
  • 猜测不是答案。充其量是评论。
  • @JesperJuhl 很抱歉我的语言对你来说太模棱两可了。我没有猜到。我知道dynamic_bitset 满足了问题所要求的所有内容,但没想到我完全理解了提问者。
  • @sehe 确实如此,但这似乎是提问者所追求的。他们似乎要求进行大量面向位的操作,并且似乎仅出于位打包的性能优势才提及整数,而动态位集确实提供了这一点(尽管具有动态内存分配)。
【解决方案2】:

您描述的操作(省略了作为整数的隐式解释)实际上是由deque 有效提供的操作。如果您可以容忍内存开销,则可以使用std::deque&lt;bool&gt;std::list&lt;bool&gt; 也可以,但开销会更高)。

如果开销太大,你可以从

struct Bits {
  std::deque<unsigned> deq;
  int ms_free,ls_free;   // unused bits in the two end words
};

并编写方法以在任一端推送位(对于右端,如果 lsb_free==0 则您将 deq.push_back() 并存储 deq.back() 否则)。比较将使用deq.size()ms_free+ls_free 来了解如何对齐两个序列。

【讨论】:

  • 布尔双端队列看起来非常有用。整数双端队列的小于运算符可能过于复杂,无法成为一个好的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多