通过旋转计算球体的算法有加法误差

Algorithm to calculate sphere by revolution has addition error

提问人:Dazckel 提问时间:12/23/2021 最后编辑:zkozaDazckel 更新时间:1/1/2022 访问量:89

问:

我正在尝试通过旋转(旋转)生成一个球体。 我的想法是以相等的步长围绕轴旋转一个点,直到 180 度,这样我就有了一个模板。 然后,我将围绕另一个轴旋转此模板(以步长为单位,最多 360 度)以生成一个球体。 算法如下:

if (o == objeto::SPHERE_P) // if the object type is Template Sphere I will rotate only 180 degrees.
        ang = M_PI;

    Vertices.resize(tamanio);
    int p = 0;
    //
    //Rotamos en función del eje.
    float nrot = 1.0/nr;
    switch (e)
    {
    case eje::AXIS_X:
        for (int i = 0; i <= nr; i++)
            for (int j = 0; j < nv; j++, p++)
            {
                float R = Distancia(plantilla[j], _vertex3f(plantilla[j].x, 0, 0));
                float a = R * cos(i*nrot*ang);
                float b = R * sin(i*nrot*ang);
                    Vertices[p] = _vertex3f(plantilla[j].x, a, b);
            }
        break;
    case eje::AXIS_Y:
        for (int i = 0; i <= nr; i++)
            for (int j = 0; j < nv; j++, p++)
            {
                float R = Distancia(plantilla[j], _vertex3f(0, plantilla[j].y, 0));
                float a = R * cos(i*nrot*ang);
                float b = R * sin(i*nrot*ang);
                Vertices[p] = _vertex3f(a, plantilla[j].y, b);
            }
        break;
    case eje::AXIS_Z:
        for (int i = 0; i <= nr; i++)
            for (int j = 0; j < nv; j++, p++)
            {
                float R = Distancia(plantilla[j], _vertex3f(0, 0, plantilla[j].z));
                float a = R * cos(i*nrot*ang);
                float b = R * sin(i*nrot*ang);
                Vertices[p] = _vertex3f(a, b, plantilla[j].z);
            }
        break;
    }
}
  • NR 是旋转次数。
  • Distancia 是球体半径,或从原点到球体上任何点的距离。
  • ab 是坐标(取决于球体旋转的轴,一个坐标不会改变)
  • NROT 为 1.0/NR
  • 顶点是一个点数组
  • nv 保存顶点数

问题

由于我使用 ,球体生成涉及一个微小的数值误差,最终会导致运行时错误。情况是最后一个顶点应该正好在初始轴上,但它的坐标不是如图所示:它们应该是 0,-5,0 这是一个小错误,但足以使我的函数(检查一个点是否在轴上)失败。 我可以修复它,使顶点坐标四舍五入,但这对我来说就像一项拙劣的工作。M_PI

谁能告诉我另一种生成旋转角度的方法,这样我就可以毫无错误地生成球体?

谢谢。

C++ 算法 几何

评论

0赞 12/23/2021
欢迎来到浮点表示和截断错误的世界。较新的假设是,在这种情况下,您可以使用比较来实现相等。考虑引入公差。
0赞 Marc Glisse 12/23/2021
你的 C 库是否提供该函数?sinpi
0赞 Bob__ 12/23/2021
考虑模拟性,仅计算 pi/4 < 0 <角中的点,并通过简单的坐标转换获得其他点。
0赞 Matt Timmermans 12/23/2021
期望浮点计算是精确的是错误的。
0赞 Aziuth 1/1/2022
为什么不遍历度数而不是弧度,然后从中计算弧度数呢?这样,如果你的度数是一个整数,或者至少是一个可以用二进制值准确表示的整数,那么唯一的错误发生在转换为弧度时,而不是在求和时。

答:

0赞 user1196549 12/23/2021 #1

一个循环,比如

for (i= 0, th= 0; i <= n; i++, th+= π/n)
    s= sin(th);

不能保证 will 的最终值是准确的,我们甚至在数值上确定吗?thπsin(π) = 0

使用更安全

for (i= 0, th= 0; i <= n; i++, th+= π/n)
    s= i < n ? sin(th) : 0;

(同样,不要指望经过的循环会完全产生。π/6sin(th) = 0.5

评论

0赞 Dazckel 12/23/2021
好的,我知道 π/6 不会产生确切的 sin(th) = 0.5,但是没有其他方法可以精确地获得 sin(th) = 0.5?即使不使用 PI?感谢您的反馈
0赞 12/23/2021
@dazckel:我不知道,但这重要吗?en.wikipedia.org/wiki/Niven%27s_theorem