对于std::bitset
,对应于无符号整数表示的比较,实现<
运算符的最优化方法是什么(它应该适用于more than 64 bits
的位集)?
一个简单的实现是:
template<std::size_t N>
bool operator<(const std::bitset<N>& x, const std::bitset<N>& y)
{
for (int i = N-1; i >= 0; i--) {
if (x[i] && !y[i]) return false;
if (!x[i] && y[i]) return true;
}
return false;
}
当我说“最优化的方式”时,我寻找的是使用位操作和元编程技巧(以及类似的东西)的实现。
编辑:我想我找到窍门了:一个用于编译时递归和右移位的模板元编程,以便将位集作为几个无符号的长整型进行比较。但是没有明确的想法如何做...
9条答案
按热度按时间qvtsj1bj1#
最明显的优化是
除此之外,使用更多的每次测试位数应该是不可能的,因为没有符合标准的方式来访问它们。您可以对
x.to_string() < y.to_string()
进行基准测试,并希望to_string()
和字符串比较都比按位访问bitset
更好地优化,但这是一个很长的机会。zy1mlcev2#
如果您愿意采用STL位集更改的解决方案,则可以使用
编译器将丢弃if的不相关分支
y53ybaqx3#
虽然你说的是位集,但你实际上是在谈论任意精度的无符号整数比较,如果是这样,那么你可能不会轻易地比 Package GMP做得更好。
从他们的网站:
GMP经过精心设计,无论是对于小操作数还是大操作数,速度都尽可能快。它的速度是通过使用全字作为基本算术类型、使用快速算法、使用高度优化的汇编代码来实现的,这些汇编代码用于许多CPU的最常见的内部循环,以及对速度的普遍强调。
考虑它们的整数函数
lp0sw83n4#
我刚刚看了源代码,但不幸的是(希望我弄错了),它们似乎没有为特定的位块提供对
const & unsigned long
的就地访问,如果它们提供了,那么您可以执行模板递归,并有效地比较每个unsigned long
,而不是无符号长整型中的每个位。毕竟,如果
A < B
,那么不仅每个最高有效位a <= b
,而且每个最高有效块A[i] <= B[i]
。我不想这么说,但我可能会在C++11的
std::array
上使用递归来实现我自己的功能。如果你可以访问这些块,那么你可以创建一个模板递归函数来很容易地实现这一点(我相信你知道,因为你要求元编程),这给了编译器一个很好的优化机会。总而言之,这不是一个很好的答案,但我会这么做。
顺便说一句,问得好。
**编辑
这应该是三种方法的时机:最新的赞成票,我描述的块策略,和一个模板递归变量。我用位集填充一个向量,然后使用指定的比较器函子重复排序。
快乐黑客!
2izufjch5#
检查XOR的最高位如何?
关于
fps
的一些想法可以在http://uwfsucks.blogspot.be/2007/07/fls-implementation.html中找到。vtwuwzda6#
好吧,有一个好的老
memcmp
。它是脆弱的,因为它依赖于std::bitset
的实现。因此可能无法使用。但是可以合理地假设模板创建了一个int
的不透明数组。并且没有其他簿记字段。这将唯一地确定
bitset
s的排序。但它可能不是人类直观的顺序。它取决于哪些位用于哪个集合成员索引。例如,索引0可以是前32位整数的LSB。或者它可以是前8位字节的LSB。我强烈建议进行单元测试,以确保它的使用方式确实有效。-〉
n7taea2i7#
只有当两个位集不同时才执行逐位比较,这已经产生了一些性能提升:
e5nqia278#
我知道这是一个老问题,但是如果你知道一个位集的最大大小,你可以创建如下的东西:
这允许您将每个
bitsets<64>
强制转换为unsigned long long
以进行快速比较。如果您想获得特定位(为了更改它或其他),可以执行bits[id / 64][id % 64]
exdqitrt9#
bitset的底层实现在几乎所有64位CPU、编译器等中使用uint 64,因为只有一种明智的方法来编写具有给定接口的类的实现,这使得很容易找出“可移植”的黑客攻击。
因此,假设你只是想“明显”的有效方法来做到这一点,你的代码不会被用来控制核武库,完全知道这将使你的保修无效,等等,这里是你正在寻找的代码:
基本上就是转换为一个uint 64数组,然后以相反的顺序逐个元素进行比较,直到发现差异。
还要注意,这是假定x86-64字节序的。