罪和cos都很慢,有没有交替?

jma*_*erx 10 c++ math

我的游戏需要移动一定的角度.为此,我通过sin和cos得到角度的矢量.不幸的是,罪和cos是我的瓶颈.我相信我不需要这么精确.是否有一个C sin&cos和查找表的替代品,它非常精确但速度非常快?

我发现了这个:

float Skeleton::fastSin( float x )
{
    const float B = 4.0f/pi;
    const float C = -4.0f/(pi*pi);

    float y = B * x + C * x * abs(x);

    const float P = 0.225f;

    return P * (y * abs(y) - y) + y; 
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这似乎不起作用.当我使用这个罪而不是C罪时,我会得到明显不同的行为.

谢谢

rer*_*run 8

查找表是标准解决方案.你也可以使用两个查找表来获得度数,一个用于十度数并使用sin(A + B)= sin(a)cos(b)+ cos(A)sin(b)

  • 关于罪,没有任何关于罪的事 (13认同)
  • Singleton面向对象的想法是一个笑话.更重要的是,该案件究竟是什么? (6认同)
  • 几乎从来都不是一个好主意.MathUtils上的静态方法没问题. (4认同)

Rei*_*ica 7

对于您fastSin(),您应该查看其文档以了解它的有效范围.您为游戏使用的单位可能太大或太小,并且缩放它们以适应该功能的预期范围可以使其更好地工作.

编辑:

其他人提到通过减去PI来使其进入所需的范围,但显然有一个函数要求fmod对浮点数/双精度进行模数除法,所以这应该这样做:

#include <iostream>
#include <cmath>

float fastSin( float x ){
    x = fmod(x + M_PI, M_PI * 2) - M_PI; // restrict x so that -M_PI < x < M_PI
    const float B = 4.0f/M_PI;
    const float C = -4.0f/(M_PI*M_PI);

    float y = B * x + C * x * std::abs(x);

    const float P = 0.225f;

    return P * (y * std::abs(y) - y) + y; 
}

int main() {
    std::cout << fastSin(100.0) << '\n' << std::sin(100.0) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

我不知道有多贵fmod,所以我接下来会尝试快速的基准测试.

基准测试结果

我编译了这个-O2并使用Unix time程序运行结果:

int main() {
    float a = 0;
    for(int i = 0; i < REPETITIONS; i++) {
        a += sin(i); // or fastSin(i);
    }
    std::cout << a << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

结果是sin大约慢了1.8倍(如果fastSin需要5秒,sin需要9).准确性似乎也很好.

如果您选择了这条路线,请确保在(-O2在gcc中)进行优化编译.

  • 该fastsin功能仅对+/- pi有效.我在固定点(16位整数)中使用它的一个版本,并在整圆上获得大约10位精度.它具有完美的对称性,完全达到0和1,这对我的应用程序非常重要. (2认同)

JMR*_*MRC 6

我知道这已经是一个古老的话题,但对于有同样问题的人来说,这里有一个提示.

在2D和3D旋转中,很多时候,所有矢量都以固定的角度旋转.而不是调用循环cos()sin()循环的每个循环,在包含值cos(angle)sin(angle)已经的循环之前创建变量.您可以在循环中使用此变量.这样只需要调用一次函数.

  • 不,但我宁愿花一个小时的调试而不是一天的调试而不是一天或一天​​.特别是如果重写代码不到一分钟.保持代码清洁没有错.这是一个很好的做法. (2认同)