仅关心速度时,如何存储二进制数据
How to store binary data when you only care about speed?
我在d维度中有n个点,假设n是100万和d 100。我所有的观点都有二进制坐标,即{0,1}^d,我只对 speed 感兴趣。
当前我的实现使用std::vector<int>
。我想知道是否可以通过更改数据结构来从更快的执行方面受益。我只是在进行插入和搜索(我不更改位)。
我发现的所有相关问题std::vector<char>
,std::vector<bool>
和std::bitset
,但所有提及的空间都应该通过使用此类结构来获得。
对于C 的二进制数据,当速度是主要问题时,适当的数据结构是什么?
中的二进制数据我打算用二进制数据填充我的数据结构,然后进行大量连续搜索(我的意思是我真的不在乎一个点的i-th坐标,如果我访问了一个点,我将连续访问其所有坐标)。我将彼此计算锤距。
如果值独立,均匀分布,并且您想找到两个独立,随机选择的点之间的锤击距离,则最有效的布局是一个堆积的位阵列。
理想情况下,这个包装的阵列将分为最大的块尺寸,您的popcnt
指令可以使用:64位。锤距离是popcnt(x_blocks[i] ^ y_blocks[i])
的总和。在具有有效非对齐访问的处理器上,与未对准读取的字节对齐可能是最有效的。在未对准的处理器上受到惩罚的处理器,应该考虑对排列行的内存开销是否值得更快。
参考的局部性可能是驱动力。因此,很明显,您将单点的D
坐标表示为连续的BitVector。std::bitset<D>
将是一个合乎逻辑的选择。
但是,要意识到的下一个重要的事情是,您可以轻松地看到当地的好处,高达4KB。这意味着您不应该选择一个点并将其与所有其他N-1点进行比较。相反,小组分别为4KB,并比较这些组。两种方式都是O(N*N)
,但第二种方式会更快。
您可以通过使用三角形不等式-Hamming(a,b)+Hamming(b,c) >= Hamming (a,c)
击败O(N*N)
。我只是想知道如何。这可能取决于您想要输出的方式。天真的输出将是一组距离,这是不可避免的O(N*N)
。
我写了一个简单的程序,以填充和连续访问数据结构与二进制数据:
-
std::vector<int>
-
std::vector<char>
-
std::vector<bool>
-
std::bitset
我使用了时间测量。我使用-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;
}
std::bitset
的代码可以在以下方式中找到:XOR BITSET将2D bitset存储为1d
对于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>
似乎是赢家。
- 如何使用 redis-plus-plus 存储二进制数据,就像我想存储结构一样?@for_stack?
- 在C++中将结构转换和存储为二进制
- 如何使用连接器 c++ 在 mySQL 表二进制(16) 字段中存储 c++ 字节数组?
- 如何将 numpy 二维数组作为一种可以用C++读取的二进制格式存储在磁盘上
- 无法在二进制文件中存储动态数组
- 将非数字字符串存储为二进制整数
- 如何将值从十进制存储为二进制,使其在 C++ 中将值保存在 6 位
- 如何存储霍夫曼转换后的二进制代码?
- 如何创建属性存储二进制文件
- Fread 是向后存储二进制
- 如何从 linux 二进制文件中存储和检索数据
- 将Protobuf字节类型存储在二进制文件中
- 如何在结构中存储二进制文件数据
- (C++) 如何从要存储在结构数组中的二进制文件中读取.dat信息?
- 保存和加载类数据存储在C 中的二进制文件中
- 在SD卡上读取和存储二进制GPS数据方面的问题
- 仅关心速度时,如何存储二进制数据
- MongoDB:我如何在c++的BSON中存储二进制数组
- 使用std::string来存储二进制数据是否不合适?
- 如何在c++数组中存储二进制输入