You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 06:24:53