c++ - 空间中的旋转 vector 和 C++ 中的高精度

标签 c++ precision

这是我在 C++ 中计算 3D 旋转的函数,该旋转由围绕轴的辐射角度定义。

 Vector rotate(const Vector& axis, const Vector& input, const double angle)    {
    double norm = 1/axis.norm();

    if(norm != 1)
        axis *= norm;

    double cos = std::cos(angle);
    double mcos = 1 - cos;
    double sin = std::sin(angle);

    double r1[3];
    double r2[3];
    double r3[3];

    double t_x, t_ym t_z;


    r1[0] = cos + std::pow(axis.x, 2)*mcos;
    r1[1] = axis.x*axis.y*mcos - axis.z * sin;
    r1[2] = axis.x*axis.z*mcos - axis.y * sin;

    r2[0] = axis.x*axis.y*mcos + axis.z*sin;
    r2[1] = cos + std::pow(axis.y, 2)*mcos;
    r2[2] = axis.x*axis.z*mcos - axis.x * sin;

    r3[0] = axis.x*axis.z*mcos - axis.y * sin;
    r3[1] = axis.z*axis.y*mcos - axis.x * sin;
    r3[2] = cos - std::pow(axis.z, 2) * mcos;

    return Vector(t_x, t_y, t_z);
}

问题是,如果您尝试将 vector 旋转 npi/4,其中 n 为 4 的倍数(所以您这样做通过四分之四的旋转来完成绕轴的旋转)错误将传播得非常快。

示例(其中 err = input-output):

input: (1.265, 3.398, 3.333)
rotation axis: (2.33, 0.568, 2.689)

n: 8 (so two completes revolutions)
output: (1.301967, 1.533389, 4.138940)
error: (0.038697, -0.864611, 0.805940)


n: 400 (so 100 completes revolutions)
error: (472..., 166..., 673...)

我能做什么?

约束:

  • 旋转是不可预测的,所以不可能像@molbdnilo 建议的那样做 angle = pi/4 *n % 2*pi 这样的事情。因为我必须链接平移和旋转以测试是否存在碰撞。

最佳答案

这是使用 float 时可能遇到的典型问题之一。

float 在奇异运算上非常精确。事实上,对于许多操作,您一定会得到可以用格式表示的最准确的结果,因此您得到的任何舍入误差完全是由于将其拟合到表示中。

但是,一旦您开始链接浮点运算,即使是这些错误也会累积起来。如果幸运的话,您可以使您的算法在数值上稳定,这样舍入误差最终会相互抵消,并且您始终保持在正确结果的范围内。不过,要做到这一点可能是一个相当大的挑战,尤其是对于复杂的计算。例如,在您的特定实现中,catastrophic cancellation 有很大的潜力在计算链中引入大的舍入误差。

更简单的解决方案是:首先避免链接 float 操作!或者更准确地说:只链接那些你可以保持数值稳定的部分。由于您提到这是针对计算机游戏的:在游戏中,您根据每一帧的相机矩阵变换几何体。您永远不会触摸内存中的几何体,而只是简单地调整相机矩阵。这样,您的源几何图形始终是新鲜的,并且每帧中的舍入误差只是来自该单一转换的误差。

同样,您通常不会增量更新相机矩阵。相反,您读取玩家的位置并从这些 vector 中从头开始查看和构建完整的矩阵。现在您剩下的唯一挑战是确保您不会将错误累积到玩家位置和 View 中,但这比确保转换管道另一端的稳定性容易得多。

关于c++ - 空间中的旋转 vector 和 C++ 中的高精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45591017/

相关文章:

c++ - for循环c++的问题

c++ - C++ iostream 的自定义操纵器

precision - 积分延迟的脉冲信号的数值问题 (fixedDelay)

控制 double

java - 使用 NumberFormat 具有两位小数的 double 值

c++ - 如何提高代码的精度

c++ - 同时重置和复制 shared_ptr 是否线程安全?

c++ - 在 GDB 中创建 C++ 字符串

javascript - JS中整数除法的精确性

c++ - 我如何在 Qt 中获取字符串的一部分?