【问题标题】:Is there a simple C library for 3d rotations with minimal rounding error?是否有用于 3d 旋转且舍入误差最小的简单 C 库?
【发布时间】:2014-07-16 17:23:26
【问题描述】:

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 doubleprecision 和combined rotations 来改善错误。对于双打,我并不完全满意(1e-3 最坏情况下的相对误差)。这是最简单的解决方案,它工作正常。仍然不会介意以常规双精度精确旋转的漂亮库。

【问题讨论】:

  • 也许你可以将你的点转换为极坐标——然后组成旋转是微不足道的,不应该累积精度误差。完成旋转后,转换回笛卡尔。
  • 非常干净的代码;干得好!
  • 问题肯定不是精度。建议问题是质量差的触发功能。除非三角函数很差,否则您应该不会遇到接近报告的精度损失的情况。

标签: c algorithm rotation linear-algebra


【解决方案1】:
  1. 更好的精度变量是不够的

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

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

[edit1] 测试

  • 我把你的代码带到 Borland BDS2006 编译为 win32 应用程序
  • 结果是:
  • original: (0.0000000000000000000,1.0000000000000000000,0.0000000000000000000)
  • rotated: (0.0000000000000000000,0.9999999999999998890,-0.0000000000000000273)
  • 也不要忘记如果你的罪过,因为采用弧度(与 C/C++ 一样)然后将其添加到 Rotate
  • 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)

【讨论】:

  • 所以对我来说最简单的事情就是切换到long double 并使用三角函数的sinl()cosl() 版本。我也需要长双精度的 PI。这给了我足够的我的目的。单独存储欧拉角并计算笛卡尔坐标,只要我需要它们也可能是一个很好的解决方案。现在我不想参与那么多。毕竟这是一个相对简单的应用程序。感谢您的输入!很棒的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多