我在D维度中有N个点,其中我们说N是100万,D 1是。我的所有点都有二进制坐标,即{0,1} ^ D,我只对 speed 感兴趣。
目前我的实施使用std::vector<int>
。我想知道我是否可以通过更改data-structure来加快执行速度。我只进行插入和搜索(我不会改变这些位)。
我发现提及std::vector<char>
,std::vector<bool>
和std::bitset
的所有相关问题,但都提到了使用此类结构应获得的空间利益。
对于C ++中的二进制数据,当速度是主要关注时,适当的数据结构是什么?
我打算用二进制数据填充我的数据结构,然后做很多连续的搜索(我的意思是,如果我访问一个点,我真的不关心某个点的第i个坐标我会连续访问它的所有坐标)。我将计算彼此之间的汉明距离。
答案 0 :(得分:3)
如果值是独立的,均匀分布的,并且您想要找到两个独立的,随机选择的点之间的汉明距离,那么最有效的布局就是一个打包的位数。
理想情况下,这个打包的数组会被嵌入到popcnt
指令工作的最大块大小:64位。汉明距离是popcnt(x_blocks[i] ^ y_blocks[i])
的总和。在具有高效未对齐访问的处理器上,具有未对齐读取的字节对齐可能是最有效的。在未对齐读取会产生损失的处理器上,应考虑对齐行的内存开销是否值得更快。
答案 1 :(得分:2)
参考地点可能是推动力。因此,将单个点的D
坐标表示为连续的位向量非常明显。 std::bitset<D>
将是一个合理的选择。
但是,要实现的下一个重要事项是,您可以轻松地看到地方性优势,最高可达4KB。这意味着你不应该选择一个点并将其与所有其他N-1点进行比较。相反,将每个组的点分组为4KB,并比较这些组。两种方式都是O(N*N)
,但第二种方式会更快。
您可以通过使用三角不等式O(N*N)
来击败Hamming(a,b)+Hamming(b,c) >= Hamming (a,c)
。我只是想知道如何。这可能取决于您想要的输出方式。天真的输出将是一组N * N的距离,并且不可避免地O(N*N)
。
答案 2 :(得分:0)
我编写了一个简单的程序,用二进制数据填充和连续访问数据结构:
std::vector<int>
std::vector<char>
std::vector<bool>
std::bitset
我使用了Time measurements。我使用-O3优化标志,N = 1 mil,D = 100.
这是向量的代码:
#include <vector>
#include <iostream>
#include <random>
#include <cmath>
#include <numeric>
#include <functional> //plus, equal_to, not2
#include <ctime>
#include <ratio>
#include <chrono>
#define T int
unsigned int hd(const std::vector<T>& s1, const std::vector<T>::iterator s2)
{
return std::inner_product(
s1.begin(), s1.end(), s2,
0, std::plus<unsigned int>(),
std::not2(std::equal_to<std::vector<T>::value_type>())
);
}
std::uniform_int_distribution<int> uni_bit_distribution(0, 1);
std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());
// g++ -Wall -O3 bitint.cpp -o bitint
int main()
{
const int N = 1000000;
const int D = 100;
unsigned int hamming_dist[N] = {0};
unsigned int ham_d[N] = {0};
std::vector<T> q;
for(int i = 0; i < D; ++i)
q.push_back(uni_bit_distribution(generator));
using namespace std::chrono;
high_resolution_clock::time_point t1 = high_resolution_clock::now();
std::vector<T> v;
v.resize(N * D);
for(int i = 0; i < N; ++i)
for(int j = 0; j < D; ++j)
v[j + i * D] = uni_bit_distribution(generator);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
duration<double> time_span = duration_cast<duration<double> >(t2 - t1);
std::cout << "Build " << time_span.count() << " seconds.\n";
t1 = high_resolution_clock::now();
for(int i = 0; i < N; ++i)
for(int j = 0; j < D; ++j)
hamming_dist[i] += (v[j + i * D] != q[j]);
t2 = high_resolution_clock::now();
time_span = duration_cast<duration<double> >(t2 - t1);
std::cout << "No function hamming distance " << time_span.count() << " seconds.\n";
t1 = high_resolution_clock::now();
for(int i = 0; i < N; ++i)
ham_d[i] = hd(q, v.begin() + (i * D));
t2 = high_resolution_clock::now();
time_span = duration_cast<duration<double> >(t2 - t1);
std::cout << "Yes function hamming distance " << time_span.count() << " seconds.\n";
return 0;
}
可以在XOR bitset when 2D bitset is stored as 1D
中找到std::bitset
的代码
对于std::vector<int>
我得到了:
Build 3.80404 seconds.
No function hamming distance 0.0322335 seconds.
Yes function hamming distance 0.0352869 seconds.
对于std::vector<char>
我得到了:
Build 8.2e-07 seconds.
No function hamming distance 8.4e-08 seconds.
Yes function hamming distance 2.01e-07 seconds.
对于std::vector<bool>
我得到了:
Build 4.34496 seconds.
No function hamming distance 0.162005 seconds.
Yes function hamming distance 0.258315 seconds.
对于std:bitset
我得到了:
Build 4.28947 seconds.
Hamming distance 0.00385685 seconds.
std::vector<char>
似乎是胜利者。