背景信息:我已经决定将我在Python中演变的3D图形脚本重新编写为C以提高速度。这涉及到我学习C.有问题的程序的一部分缓存关于3D网格的法线信息。
这里依次调用3个向量运算(非常标准:向量减法得到边向量,交叉乘积和平均值),我希望尽可能快,所以我试图避免存储任何不必要的东西......并且复制我的结构太多次了。但是,我也知道如果我返回指针,我将指向mem空间,它不再有效。
这是我如何尝试编写所有三个函数(一般来说:struct copy in,struct copy out,而不是指针)。
typedef struct vector vector;
struct vector{
double x,y,z;
};
vector vect(vector a, vector b){
vector res;
res.x = b.x - a.x;
res.y = b.y - a.y;
res.z = b.z - a.z;
return res;
}
vector cross(vector a, vector b){
vector res;
res.x = a.y*b.z - a.z*b.y;
res.y = a.z*b.x - a.x*b.z;
res.z = a.x*b.y - a.y*b.x;
return res;
}
vector avg (vector a, vector b){
vector res;
res.x = (a.x + b.x)/2;
res.y = (a.y + b.y)/2;
res.z = (a.z + b.z)/2;
return res;
}
这就是它的名字:
m->Tpolynormals[i] = avg(cross( vect(*p->verts[0], *p->verts[1]),
vect(*p->verts[1], *p->verts[2]) ),
cross( vect(*p->verts[2], *p->verts[3]),
vect(*p->verts[3], *p->verts[0]) )
);
这是否相当有效还是有更快的方法吗?我知道我可以尝试并且#34;让它工作"但是在这一点上我想确保基础是坚实的。 - 谢谢
编辑:在上面添加了我的结构定义,正如有人明显指出的那样,呃。坐标是双倍的(它是我的3D包输出的),系统是64位。
答案 0 :(得分:5)
"避免(初学者')分配错误" vs."我希望尽可能快,"
哪个更重要?
如果代码需要尽可能快,请尝试多种方法并对其进行分析,以了解最适合您的方法。你会犯错误。
sizeof vector
位于边界区域,为最佳状态提供一般答案,通过值或其地址传递vector
。最好兼顾
1)按值传递vector
。 OP似乎很清楚。
vector vect(vector a, vector b){
vector res;
res.x = b.x - a.x;
res.y = b.y - a.y;
res.z = b.z - a.z;
return res;
}
2)将vector
通过其地址。创建中间结果位置。这似乎是OP不确定的部分。
void V_vect(vector *res, const vector *a, const vector *b){
res->x = b->x - a->x;
res->y = b->y - a->y;
res->z = b->z - a->z;
}
// usage example
vector res1;
vector res2;
V_vect(&res1, p->verts[0], p->verts[1]);
V_vect(&res2, p->verts[1], p->verts[2]);
vector res3;
V_cross(&res3, &res1, &res2);
V_vect(&res1, p->verts[2], p->verts[3]);
V_vect(&res2, p->verts[3], p->verts[0]);
vector res4;
V_cross(&res4, &res1, &res2);
V_avg(&m->Tpolynormals[i], &res3, &res4);
特别建议避免在同一个呼叫中重复使用内存,如下所示。在功能和代码性能方面,这可能是一个新手的错误。
V_cross(&res2, &res1, &res2);
传递地址时加速的方法是使用restrict
。这允许编译器知道调用代码正在使用指向不重叠区域的指针。这允许某些编译器优化。
void V_vect(vector * restrict res, const vector * restrict a, const vector * restrict b){
res->x = b->x - a->x;
res->y = b->y - a->y;
res->z = b->z - a->z;
}
对于restrict
,下面第一个调用是未定义的行为,因为它与vector
重叠。
// V_cross(&res2, &res1, &res2); // bad
V_cross(&res4, &res1, &res2); // good
尝试各种方法(包括@Jonathan Leffler compound literal idea和@Jonathan Leffler inline idea)并使用适合您的方法。
答案 1 :(得分:2)
如果要最小化复制的数据量,可以将指针传递给输入和输出参数。但这意味着您不能像上面那样将函数调用链接在一起,这意味着您需要使用临时变量来保存每次调用的结果。
例如:
void vect(vector *a, vector *b, vector *res){
res->x = b->x - a->x;
res->y = b->y - a->y;
res->z = b->z - a->z;
}
// similarly for the other two
然后给他们打电话:
vector vect1, vect2, vect3, vect4, cross1, cross2;
vect(p->verts[0], p->verts[1], &vect1);
vect(p->verts[1], p->verts[2], &vect2);
vect(p->verts[2], p->verts[3], &vect3);
vect(p->verts[3], p->verts[0], &vect4);
cross(&vect1, &vect2, &cross1);
cross(&vect3, &vect4, &cross2);
avg(&cross1, &cross2, &m->Tpolynormals[i]);