我在程序的最内部循环中有以下代码
struct V {
float val [200]; // 0 <= val[i] <= 1
};
V a[600];
V b[250];
V c[250];
V d[350];
V e[350];
// ... init values in a,b,c,d,e ...
int findmax(int ai, int bi, int ci, int di, int ei) {
float best_val = 0.0;
int best_ii = -1;
for (int ii = 0; ii < 200; ii++) {
float act_val =
a[ai].val[ii] +
b[bi].val[ii] +
c[ci].val[ii] +
d[ci].val[ii] +
e[ci].val[ii];
if (act_val > best_val) {
best_val = act_val;
best_ii = ii;
}
}
return best_ii;
}
我不在乎它是否会是一些聪明的算法(但这将是最有趣的)或一些C ++技巧或内在函数或汇编程序。但我需要让findmax功能更有效。
提前非常感谢。
修改 分支似乎是最慢的操作(错误预测?)。
答案 0 :(得分:4)
如果编译器在缩短跳转时遇到困难,这可能会有所帮助:
int findmax(int ai, int bi, int ci, int di, int ei) {
float best_val = 0.0;
int best_ii = -1;
float* a_it = &a[ai].val[0]
float* b_it = &b[bi].val[0]
float* c_it = &c[ci].val[0]
float* d_it = &d[di].val[0] // assume typo ci->di
float* e_it = &e[ei].val[0] // assume typo ci->ei
for (int ii = 0; ii < 200; ii++) {
float act_val = *(a_it++) + *(b_it++) + *(c_it++) + *(d_it++) + *(e_it++);
best_val = (act_val <= best_val) ? best_val : act_val; // becomes _fsel
best_ii = (act_val <= best_val) ? best_ii : ii; // becomes _fsel
}
return best_ii;
}
在缓存未命中方面生成和表可能会更快我将稍后发布:
int findmax(int ai, int bi, int ci, int di, int ei) {
float best_val = 0.0;
int best_ii = -1;
float* its[] = {&a[ai].val[0], &a[bi].val[0], &a[ci].val[0], &a[di].val[0], &a[ei].val[0] };
V sums;
for (int ii = 0; ii < 200; ii++) {
sums.val[ii] = * (++its[0]);
}
for (int iter = 1 ; iter < 5; ++iter) {
for (int ii = 0; ii < 200; ii++) {
sums.val[ii] += * (++its[iter]);
}
}
}
for (int ii = 0; ii < 200; ii++) {
best_val = (sums.val[ii] <= best_val) ? best_val : sums.val[ii]; // becomes _fsel
best_ii = (sums.val[ii] <= best_val) ? best_ii : ii; // becomes _fsel
}
return best_ii;
}
答案 1 :(得分:2)
如果不检查每个总和,我没有看到任何方法这样做,这使得这是一个O(n)问题。但由于您的数据是线性布局的,因此英特尔/ AMD MMX或SSE指令可能有所帮助。有关Microsoft内在函数的实现,请参阅此链接:
http://msdn.microsoft.com/en-us/library/y0dh78ez(VS.71).aspx
答案 2 :(得分:2)
好吧,我认为没有明显的算法优化空间。理论上只能计算五个向量的总和,直到很明显无法达到最大值,但这会增加很多开销,只能求和五个数。您可以尝试使用多个线程并为线程分配范围,但是当您只有200个非常短的工作项时,您必须考虑线程创建开销。
所以我倾向于说在x86上使用Assembler和MMX或SSE指令,或者可能是(机器特定的)C ++,提供访问此指令的库是最好的选择。
答案 3 :(得分:2)
除非编译器为您优化它们,否则在循环中计算a[ai]
等将花费您一些时间(无论多少时间),因为它们在findmax
的持续时间内是固定的。鉴于此,您可以尝试以下方式:
int findmax(int ai, int bi, int ci, int di, int ei) {
float best_val = std::numeric_limits<float>::min();
int best_ii = 0;
const V& a(a[ai]);
const V& b(b[bi]);
const V& c(c[ci]);
const V& d(d[di]);
const V& e(e[ei]);
for (int ii = 0; ii < 200; ++ii) {
float act_val = a.val[ii] + b.val[ii] + c.val[ii] +
d.val[ii] + e.val[ii];
if (act_val > best_val) {
best_val = act_val;
best_ii = ii;
}
}
return best_ii;
}
其他改进代码的方法可能是改变数据的表示方式,从而导致findmax
算法不同(但更快)。
答案 4 :(得分:1)
尝试一次迭代所有向量。以下是两个向量的示例:
for (float *ap = a[ai].val, *bp = b[bi].val; ap - a[ai].val < 200; ap++, bp ++) {
float act_val = *ap + *bp;
// check for max and return if necessary
}
答案 5 :(得分:1)
答案 6 :(得分:0)
如果没有关于a
,b
,c
,d
和e
中存储的数据(值)的其他信息,您实际上得不会那么快{{1}}。你必须检查每一笔金额,以确定哪一笔是最大的。
第N个元素查询会变得更糟,但幸运的是,你没有问过那个。