gpt4 book ai didi

c++ - std::tuple 比 std::array 快吗?

转载 作者:行者123 更新时间:2023-12-03 17:41:06 31 4
gpt4 key购买 nike

我有一个固定列数 = 4 的二维数组,但行数非常大。我发现使用 vector<tuple>而不是 vector<array>或比 vector<vector> 快近 2 倍,快 5 倍.虽然使用 tuple真是令人头疼。我定义了一个访问函数来解决它:

typedef tuple<int,int,int,int> Tuple;
// access the i-th element
inline int &tget (Tuple &t, int i) {
switch (i) {
case 0: return std::get<0>(t);
case 1: return std::get<1>(t);
case 2: return std::get<2>(t);
case 3: return std::get<3>(t);
}
}
vector<Tuple> array;
// this gives the element in i-th row and j-th column
tget(array[i],j);

我发现这非常令人惊讶,并且想知道这种性能提升来自哪里,以及是否有语法类似于 vector<vector> 的简洁解决方案或 vector<array>使用下标 operator[]tuple 具有相同的性能?

更新 :
我正在使用 gcc4.8c++11标准,我使用 -O3用于优化。
因为人们问操作操作是相当基本的。首先,二维数组最多填充 1M 行。首先我保留空间然后使用 push_back添加元素的功能。然后我对数组进行排序,最后对它进行二进制搜索。

这是我写的代码块。输入将是几个测试用例(=T),每个测试用例取一个整数(N 到 20),然后在 lens 中再读取 N 个整数.然后由于函数的指数性质,总和变得相当大(4 ^(N/2)高达大约一百万)。要在数组和元组之间进行测试,请切换 typedef 并注释/取消注释访问函数中的返回行。有四行/ block 必须注释/取消注释才能在 array 之间来回切换和 tuple ,并且这些行在注释中指定( // if array // if tuple 注释):
#include <iostream>
#include <algorithm>
#include <vector>
#include <tuple>
#include <array>
using namespace std;

typedef vector<int>::iterator VecIt;

// HERE you can switch between the two types
typedef tuple<int,int,int,int> Tuple; // define it as a tuple
//typedef array<int,4> Tuple; // define it as array
inline int &tget (Tuple &t, int i) {
// return t[i]; // if it's an array, uncomment This too

// if it's an array comment the switch case
switch (i) {
case 0: return std::get<0>(t);
case 1: return std::get<1>(t);
case 2: return std::get<2>(t);
case 3: return std::get<3>(t);
default:
cerr << "tuple index out of bound" << endl;
}
}

void comp_sums(VecIt v, VecIt vend, vector<Tuple> &sums){
if (v==vend)
return;
int size = sums.size();
for (int i=0; i<size; i++) {
for (int j=1; j<4; j++){
sums.push_back(sums[i]);
tget(sums.back(),j) += *v;
}
tget(sums[i],0) += *v;
}
v++;
comp_sums(v, vend, sums);
}

void docase( ) {
int N;
cin >> N;
vector<int> lens(N);
int lsum = 0;
for (int i=0; i<N; i++) {
cin >> lens[i];
lsum += lens[i];
}
if (lsum % 4 != 0 ) {
cout << 0 << endl;
return;
}
lsum = lsum/4;

vector<Tuple> sums1, sums2;
Tuple z(0,0,0,0); // if it's a tuple
//Tuple z = {0,0,0,0}; // If it's an array
sums1.push_back(z); sums1.reserve(1<<N/2);
sums2.push_back(z); sums2.reserve(1<<N/2);
comp_sums(lens.begin()+1, lens.begin()+N/2, sums1);
comp_sums(lens.begin()+N/2+1, lens.end(), sums2);
sort(sums1.begin(), sums1.end());
sort(sums2.begin(), sums2.end());
long count = 0;
for (int i=0; i<sums1.size(); i++) {
for (int k=0; k<4; k++) {
//Tuple t({lsum,lsum,lsum,lsum}); // if it's an array
Tuple t(lsum,lsum,lsum,lsum); // if it's a tuple
for (int j=0; j<4; j++)
tget(t,j) -= tget(sums1[i],(j+k)%4);
tget(t,k) -= lens[0];
tget(t,0) -= lens[N/2];
bool neg = false;
for (int j=0; j<4; j++)
if (tget(t,j)<0){
neg = true;
break;
}
if (neg)
continue;
auto LB = lower_bound(sums2.begin(), sums2.end(), t);
auto UB = upper_bound(LB, sums2.end(), t);
count += (UB - LB);
}
}
cout << count/6 << endl;
}


int main() {
std::ios_base::sync_with_stdio(false);
int T;
cin >> T;
while (T--) docase();
}

这也是我使用的一个测试输入。第一行说有 T=18 个单独的测试用例。每个测试用例的第一行是 N(最多 20 个),然后是 N 个整数。这里是。该算法具有指数增长,因此小数字并不意味着它只是几个操作。同样在测量时间时,我已经考虑了 I/O:
18
8
132391 123854 21536 19482 133025 10945 121800 10311
8
12 4 12 4 4 12 12 24
8
131723 16253 23309 132227 125171 12253 16757 136227
8
8 4 4 8 4 8 12 24
8
12 12 12 8 4 8 12 28
8
115021 114654 112093 17443 20371 17810 17274 115190
8
8 8 4 4 12 4 12 20
8
12 4 4 4 4 12 12 28
8
8 12 8 12 8 4 12 28
8
4 12 8 12 8 8 4 24
20
34836 56869 24112 27796 198091 196472 50364 27364 29572 53701 52981 25779 202644 204884 53840 30056 48705 53092 43751 18419
20
207447 26867 41968 35977 36384 57042 40981 30191 47705 26907 248361 26003 53715 48237 27691 192772 60507 58194 20754 245913
20
34836 56869 24112 27796 198091 196472 50364 27364 29572 53701 52981 25779 202644 204884 53840 30056 48705 53092 43751 18419
20
207447 26867 41968 35977 36384 57042 40981 30191 47705 26907 248361 26003 53715 48237 27691 192772 60507 58194 20754 245913
20
4 2 2 4 4 2 4 2 4 2 2 4 4 3 3 4 2 3 4 1
20
2 3 2 2 3 2 3 4 3 2 4 4 4 3 2 3 4 4 3 3
20
4 4 4 4 3 3 3 2 2 4 2 4 2 2 4 2 2 2 2 1
20
4 4 2 3 4 3 4 3 2 4 4 2 2 4 3 4 3 3 2 4

最佳答案

我的猜测是瓶颈是 operator<std::tuplestd::array .如果您尝试使用此用户定义的结构:

struct my_struct {
int a, b, c, d;
};

inline bool operator<(my_struct const& lhs, my_struct const& rhs) {
return std::tie(lhs.a, lhs.b, lhs.c, lhs.d) <
std::tie(rhs.a, rhs.b, rhs.c, rhs.d);
}

这比 std::tuple 慢大约 5 倍。或 std::array (在我的电脑上用 MinGW 和 Wandbox 测试过)。

此外, operator< std::tuple 的装配和 std::array是不同的(与 -O3 ),这可能解释了 std::tuple 之间的性能差异和 std::array .
fun(std::array<int, 4ul> const&, std::array<int, 4ul> const&):
mov ecx, DWORD PTR [rdi]
cmp DWORD PTR [rsi], ecx
lea rdx, [rsi+16]
lea rax, [rdi+16]
jg .L32
jl .L31
.L25:
add rdi, 4
add rsi, 4
cmp rax, rdi
je .L36
mov ecx, DWORD PTR [rsi]
cmp DWORD PTR [rdi], ecx
jl .L32
jle .L25
.L31:
xor eax, eax
ret
.L32:
mov eax, 1
ret
.L36:
cmp rdx, rsi
setne al
ret

fun(std::tuple<int, int, int, int> const&, std::tuple<int, int, int, int> const&):
mov edx, DWORD PTR [rsi+12]
cmp DWORD PTR [rdi+12], edx
mov eax, 1
jl .L11
mov eax, 0
jg .L11
mov ecx, DWORD PTR [rsi+8]
cmp DWORD PTR [rdi+8], ecx
mov eax, 1
jl .L11
mov eax, 0
jg .L11
mov ecx, DWORD PTR [rsi+4]
cmp DWORD PTR [rdi+4], ecx
mov eax, 1
jl .L11
mov eax, 0
jg .L11
mov eax, DWORD PTR [rsi]
cmp DWORD PTR [rdi], eax
setl al
.L11:
rep ret

关于c++ - std::tuple 比 std::array 快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48445291/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com