C++ 张量积算法优化 给定数据,产生结果的最快(最少执行)是什么?假设数据的大小是可变的,但总是一个因子4(例如,4、8、12等) 没有推进。我正试图保持我的依赖性小。STL算法还可以 提示:结果数组大小应始终为4^(多个大小)(例如,4、16、64等) 奖励:如果你能计算出只给定x,y,z的结果
其他示例:C++ 张量积算法优化 给定数据,产生结果的最快(最少执行)是什么?假设数据的大小是可变的,但总是一个因子4(例如,4、8、12等) 没有推进。我正试图保持我的依赖性小。STL算法还可以 提示:结果数组大小应始终为4^(多个大小)(例如,4、16、64等) 奖励:如果你能计算出只给定x,y,z的结果,c++,algorithm,optimization,C++,Algorithm,Optimization,其他示例: double data[12] = {1, z, z^2, z^3, 1, y, y^2, y^3, 1, x, x^2, x^3}; double result[64] = {1, z, z^2, z^3, y, zy, (z^2)y, (z^3)y, y^2, z(y^2), (z^2)(y^2), (z^3)(y^2), y^3, z(y^3), (z^2)(y^3), (z^3)(y^3), x, zx, (z^2)x, (z^3)x, yx, zyx, (z^2)yx, (
double data[12] = {1, z, z^2, z^3, 1, y, y^2, y^3, 1, x, x^2, x^3};
double result[64] = {1, z, z^2, z^3, y, zy, (z^2)y, (z^3)y, y^2, z(y^2), (z^2)(y^2), (z^3)(y^2), y^3, z(y^3), (z^2)(y^3), (z^3)(y^3), x, zx, (z^2)x, (z^3)x, yx, zyx, (z^2)yx, (z^3)yx, (y^2)x, z(y^2)x, (z^2)(y^2)x, (z^3)(y^2)x, (y^3)x, z(y^3)x, (z^2)(y^3)x, (z^3)(y^3)x, x^2, z(x^2), (z^2)(x^2), (z^3)(x^2), y(x^2), zy(x^2), (z^2)y(x^2), (z^3)y(x^2), (y^2)(x^2), z(y^2)(x^2), (z^2)(y^2)(x^2), (z^3)(y^2)(x^2), (y^3)(x^2), z(y^3)(x^2), (z^2)(y^3)(x^2), (z^3)(y^3)(x^2), x^3, z(x^3), (z^2)(x^3), (z^3)(x^3), y(x^3), zy(x^3), (z^2)y(x^3), (z^3)y(x^3), (y^2)(x^3), z(y^2)(x^3), (z^2)(y^2)(x^3), (z^3)(y^2)(x^3), (y^3)(x^3), z(y^3)(x^3), (z^2)(y^3)(x^3), (z^3)(y^3)(x^3)};
运行此基准测试后,我选择了接受的应答代码:。基本上,运行了前两个代码,赢得了执行时间最小的代码。您应该使用动态算法。也就是说,您可以使用以前的结果。例如,您保留y^2结果,并在计算(y^2)z时使用它,而不是再次计算它。您应该寻找快速解决方案,和 还有一件事:在我看来,它是有限元解算器的基础。通常编写自己的BLAS解算器不是一个好主意。不要重新发明轮子!我认为你应该使用像or这样的BLAS解算器。
void张量(std::vector&result,double x,double y,double z){
result.resize(64);//如果大小已经合适,则几乎为noop
双tz=z*z;
双y=y*y;
双tx=x*x;
数组数据={0,0,tz,tz*z,1,y,ty,ty*y,1,x,tx,tx*x};
寄存器std::vector::iterator iter=result.begin();
注册int-yi;
寄存器双xy;
对于(register int xi=0;xi一个好的编译器会自动向量化它,我想我的编译器都不好:
void Tensor(std::vector<double>& result, double x, double y, double z) {
result.resize(64); //almost noop if already right size
double tz = z*z;
double ty = y*y;
double tx = x*x;
std::array<double, 12> data = {0, 0, tz, tz*z, 1, y, ty, ty*y, 1, x, tx, tx*x};
register std::vector<double>::iterator iter = result.begin();
register int yi;
register double xy;
for(register int xi=0; xi<4; ++xi) {
for(yi=0; yi<4; ++yi) {
xy = data[4+yi]*data[8+xi];
*iter = xy; //a smart compiler can do these four in parallell
*(++iter) = z*xy;
*(++iter) = data[2]*xy;
*(++iter) = data[3]*xy;
++iter; //workaround for speed!
}
}
}
void张量(常数双*限制数据,
整数维,
双重*限制结果){
结果[0]=1.0;
对于(int i=0;i
#包括
#包括
#包括
void张量(std::vector&result,const std::vector&variables,size\u t index)
{
双p1=变量[索引];
双p2=p1*p1;
双p3=p1*p2;
if(index==variables.size()-1){
结果:推回(1);
结果:推回(p1);
结果:推回(p2);
结果:推回(p3);
}否则{
张量(结果、变量、指数+1);
ptrdiff_t size=result.size();
对于(int j=0;jDo您有一个太慢的算法,还是您需要一个算法?@Als不是家庭作业;它是为了工作。@Seth我已经有了一个解决方案,但它很慢,并且引入了外部依赖项(特别是Eigen)执行Kronecker产品。如果你使用的是Eigen,而且速度很慢,那么要么你做得不对,要么你做得更快,这意味着英特尔数学库的魔力。我很可能使用Eigen做得不对;我会同意的。基本上,我不能让Eigen在地图上执行Kronecker产品,而不创建的副本E> map < /COD>这样执行内存分配,然后减慢执行。使用<代码>登记INTI席席,YI;登记双XY;<代码>循环之前和<代码> XY=数据[4 +Yi] *数据[8 +XI];*ITER=XY;*(+ITER)= Z*XY;*(+ITER)=数据[2 ] *XY;*(+ITER)=数据[3 ]*xy;++iter;
在循环体中。iter++
通常实现为iterator temp(*this);++(*this);return temp;
。我通常会忽略register
关键字,因为我的编译器会忽略它。我添加它是为了防止某些编译器仍然关心它。我知道++iter
vsiter++
,但是因为它在循环中,所以优化在这里不起作用。而且,因为向量::迭代器
基本上是一个指针,所以这并不是真正的减速。我没有完全理解这个问题,也没有正确阅读答案,但是努力了+1!我已经运行了代码,它正确地完成了我上面展示的示例案例。所以我对答案投了赞成票。我没有接受它的原因是它对一般案例不起作用。我现在正在处理它,当我得到你的建议时thod expanded我会接受答案。哪种通用情况?更多变量?不同类型的变量?0-N的幂?这有点作用。我使用VS 2010,并且restrict
关键字无效;它使用\u restrict
。此外,由于某种原因,在使用编译器优化后运行代码时,它不起作用;不过如果我在没有优化的情况下运行它,它确实可以工作。删除VS中的\u restrict
关键字可以修复编译器优化错误。@Ryan:显然,对其中的几个答案进行计时。这个答案多次写入数组的某些元素,但代码太小,可能在缓存中执行得更好,因此可能比其他方法更快.@Mooing Duck这一个多次写入数组中的某些元素这一个并没有假设每个四元数组的第一个元素是1。在这个假设下,避免额外的写入是很容易的。@d:事实上,是的。你说得对。我现在知道了。但是,如果四元数组的第一个元素每个四边形为1。
void Tensor(std::vector<double>& result, double x, double y, double z) {
result.resize(64); //almost noop if already right size
double tz = z*z;
double ty = y*y;
double tx = x*x;
std::array<double, 12> data = {0, 0, tz, tz*z, 1, y, ty, ty*y, 1, x, tx, tx*x};
register std::vector<double>::iterator iter = result.begin();
register int yi;
register double xy;
for(register int xi=0; xi<4; ++xi) {
for(yi=0; yi<4; ++yi) {
xy = data[4+yi]*data[8+xi];
*iter = xy; //a smart compiler can do these four in parallell
*(++iter) = z*xy;
*(++iter) = data[2]*xy;
*(++iter) = data[3]*xy;
++iter; //workaround for speed!
}
}
}
void tensor(const double *restrict data,
int dimensions,
double *restrict result) {
result[0] = 1.0;
for (int i = 0; i < dimensions; i++) {
for (int j = (1 << (i * 2)) - 1; j > -1; j--) {
double alpha = result[j];
{
double *restrict dst = &result[j * 4];
const double *restrict src = &data[(dimensions - 1 - i) * 4];
for (int k = 0; k < 4; k++) dst[k] = alpha * src[k];
}
}
}
}
#include <vector>
#include <cstddef>
#include <cmath>
void Tensor(std::vector<double>& result, const std::vector<double>& variables, size_t index)
{
double p1 = variables[index];
double p2 = p1*p1;
double p3 = p1*p2;
if (index == variables.size() - 1) {
result.push_back(1);
result.push_back(p1);
result.push_back(p2);
result.push_back(p3);
} else {
Tensor(result, variables, index+1);
ptrdiff_t size = result.size();
for(int j=0; j<size; ++j)
result.push_back(result[j]*p1);
for(int j=0; j<size; ++j)
result.push_back(result[j]*p2);
for(int j=0; j<size; ++j)
result.push_back(result[j]*p3);
}
}
std::vector<double> Tensor(const std::vector<double>& params) {
std::vector<double> result;
double rsize = (1<<(2*params.size());
result.reserve(rsize);
Tensor(result, params);
return result;
}
int main() {
std::vector<double> params;
params.push_back(3.1415926535);
params.push_back(2.7182818284);
params.push_back(42);
params.push_back(65536);
std::vector<double> result = Tensor(params);
}