C++中原地修改与拷贝返回为何产生不同浮点值?
原地修改vec3旋转函数导致浮点计算差异的原因
问题背景
作为C++新手,我最初实现了基于返回新对象的vec3旋转函数,后来为了避免创建临时对象改成原地修改版本,但发现两者输出的浮点值存在差异,且差异会随循环累积放大。
原始实现(返回新对象)
typedef struct { double x; double y; double z; } vec3_t; vec3_t vec3_rotate_x(const vec3_t& v, double angle) { vec3_t rotated_vector = { .x = v.x, .y = v.y * cos(angle) - v.z * sin(angle), .z = v.y * sin(angle) + v.z * cos(angle) }; return rotated_vector; } vec3_t vec3_rotate_y(const vec3_t& v, double angle) { vec3_t rotated_vector = { .x = v.x * cos(angle) - v.z * sin(angle), .y = v.y, .z = v.x * sin(angle) + v.z * cos(angle) }; return rotated_vector; } vec3_t vec3_rotate_z(const vec3_t& v, double angle) { vec3_t rotated_vector = { .x = v.x * cos(angle) - v.y * sin(angle), .y = v.x * sin(angle) + v.y * cos(angle), .z = v.z }; return rotated_vector; }
使用方式:
for (vec3_t transformed_vertex : face_vertices) { transformed_vertex = vec3_rotate_x(transformed_vertex, mesh.rotation.x); transformed_vertex = vec3_rotate_y(transformed_vertex, mesh.rotation.y); transformed_vertex = vec3_rotate_z(transformed_vertex, mesh.rotation.z); ... }
优化后的原地修改版本
void vec3_rotate_x(vec3_t& v, double angle) { v.y = v.y * cos(angle) - v.z * sin(angle); v.z = v.y * sin(angle) + v.z * cos(angle); } void vec3_rotate_y(vec3_t& v, double angle) { v.x = v.x * cos(angle) - v.z * sin(angle); v.z = v.x * sin(angle) + v.z * cos(angle); } void vec3_rotate_z(vec3_t& v, double angle) { v.x = v.x * cos(angle) - v.y * sin(angle); v.y = v.x * sin(angle) + v.y * cos(angle); }
使用方式:
for (vec3_t transformed_vertex : face_vertices) { vec3_rotate_x(transformed_vertex, mesh.rotation.x); vec3_rotate_y(transformed_vertex, mesh.rotation.y); vec3_rotate_z(transformed_vertex, mesh.rotation.z); ... }
输出差异
单次循环输出对比:
// 未优化代码输出 { x=-0.97990184160224847 y=-0.99979901171636831 z=-1.0198991700141220 } // 优化后代码输出 { x=-0.97990284650179404 y=-0.99969953513531573 z=-1.0196971968296114 }
原因分析
核心问题是原地修改时,计算第二个分量时使用了已经被修改过的第一个分量值,而原始代码是基于输入向量的所有原始值计算新分量。以三个旋转函数为例:
- vec3_rotate_x:
原始代码中,y和z的计算都依赖输入向量v的原始y、z值;但优化后的代码先修改了v.y,计算v.z时用的是更新后的v.y,而非原始值,导致计算结果偏差。 - vec3_rotate_y:
原始代码中z的计算依赖原始v.x,但优化后先修改了v.x,计算v.z时使用的是新的v.x,逻辑错误。 - vec3_rotate_z:
原始代码中y的计算依赖原始v.x,优化后先修改v.x,计算v.y时用新值,导致结果错误。
浮点运算的精度误差会因为每一步的逻辑偏差被累积,最终导致差异逐渐放大。
修复方法
在原地修改前,先将向量的原始分量保存到临时变量,再用临时变量计算新值,确保所有计算都基于原始输入:
void vec3_rotate_x(vec3_t& v, double angle) { double orig_y = v.y; double orig_z = v.z; v.y = orig_y * cos(angle) - orig_z * sin(angle); v.z = orig_y * sin(angle) + orig_z * cos(angle); } void vec3_rotate_y(vec3_t& v, double angle) { double orig_x = v.x; double orig_z = v.z; v.x = orig_x * cos(angle) - orig_z * sin(angle); v.z = orig_x * sin(angle) + orig_z * cos(angle); } void vec3_rotate_z(vec3_t& v, double angle) { double orig_x = v.x; double orig_y = v.y; v.x = orig_x * cos(angle) - orig_y * sin(angle); v.y = orig_x * sin(angle) + orig_y * cos(angle); }
这样修改后的原地函数逻辑就和原始版本完全一致,不会再出现计算差异。
内容的提问来源于stack exchange,提问作者Adam Hartleb
相关产品推荐
相关产品推荐

