是否有一个简单的C库用于3d旋转,具有最小的舍入误差?

时间:2014-07-15 10:54:42

标签: c algorithm rotation linear-algebra

3d中矢量旋转的简单实现会产生巨大的舍入误差,尤其是在执行不同轴周围的多次旋转时。 simple 1-axis example显示基本问题。我有一个代码,我在x轴和y轴周围旋转几次。在某些情况下,我在小数点后第二位出现错误(例如,向量的长度在旋转之前为1,之后为0.9)。我对相对错误< 1e-5感到满意。

void Rotate_x(double data[3], double agl) {
    agl *= M_PI/180.0;
    double c = cos(agl);    double s = sin(agl);
    double tmp_y = c*data[1] - s*data[2];
    double tmp_z = s*data[1] + c*data[2];
    data[1] = tmp_y;        data[2] = tmp_z;
}

是否有人可以指向一个库或某些代码,它可以绕坐标轴旋转点,但错误最小?

我发现的一切都是臃肿的线性代数库,对我来说是过度的。

修改: 我转到long double精度和combined rotations来改善错误。对于双打,我并不完全满意(在最坏的情况下1e-3相对错误)。这是最简单的解决方案,它可以正常工作。仍然不会介意一个很好的库,它可以准确地进行常规双精度旋转。

1 个答案:

答案 0 :(得分:2)

  1. 更好的精度变量是不够的

    • 你需要更精确的sin,cos函数来提高准确性
    • 所以通过Taylor系列扩展来创建自己的功能
    • 并使用...然后比较结果
    • 并增加多项式阶数,直到精度停止上升或再次开始下降
  2. 如果您对同一数据应用了许多转换

    • 然后创建累积变换矩阵
    • 然后检查它是否是正交/正交
    • 如果没有修复(使用交叉产品)
    • 我将它用于3D渲染对象矩阵(随着时间的推移,许多累积变换)
    • 但在您的情况下,这也会增加错误(如果在校正期间选择了错误的轴顺序)
    • 这更适合确保物体随时间保持相同的尺寸/形状......
  3. [edit1]测试

    • 我把你的代码带到Borland BDS2006编译为win32 app
    • ,结果是:
    • original: (0.0000000000000000000,1.0000000000000000000,0.0000000000000000000)
    • rotated: (0.0000000000000000000,0.9999999999999998890,-0.0000000000000000273)
    • 也不要忘记你的罪是否因为弧度(因为通常用于C / C ++)然后将其添加到旋转
    • agl*=M_PI/180.0;
    • 您使用的是什么编译器/平台?

    这是我的旋转看起来像

    void Rotate(double *data,double agl)
        {
        agl*=M_PI/180.0;
        double c = cos(agl);    double s = sin(agl);
        double tmp_y = c*data[1] - s*data[2];
        double tmp_z = s*data[1] + c*data[2];
        data[1] = tmp_y; data[2] = tmp_z;
        }
    

    [edit2] 32/64位比较

    [double] //64bit floating point
    (0.0000000000000000000,1.0000000000000000000,0.0000000000000000000)
    (0.0000000000000000000,0.9999999999999998890,-0.0000000000000000273)
    [float] //32bit floating point
    (0.0000000000000000000,1.0000000000000000000,0.0000000000000000000)
    (0.0000000000000000000,0.9999999403953552246,-0.0000000146747787255)