我的游戏需要移动一定的角度。为此,我通过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;
}
不幸的是,这似乎不起作用。当我使用这个罪而不是C罪时,我会得到明显不同的行为。
由于
答案 0 :(得分:8)
查找表是标准解决方案。你也可以使用两个查找表进行度数,一个使用十进制度数并利用sin(A + B)= sin(a)cos(b)+ cos(A)sin(b)
答案 1 :(得分: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;
}
我不知道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;
}
结果是sin
慢了约1.8倍(如果fastSin
需要5秒,sin
需要9)。准确性似乎也很不错。
如果您选择这条路线,请确保在(gcc中的-O2
)上进行优化编译。
答案 2 :(得分:6)
我知道这已经是一个古老的话题,但对于有相同问题的人来说,这是一个小贴士。
在2D和3D旋转中,很多时候,所有矢量都以固定的角度旋转。而不是在循环的每个循环中调用cos()
或sin()
,而是在循环之前创建变量,其中包含cos(angle)
或sin(angle)
的值。您可以在循环中使用此变量。这样只需要调用一次函数。
答案 3 :(得分:3)
您可以计算256个值的表S,从sin(0)到sin(2 * pi)。然后,为了选择sin(x),在[0,2 * pi]中返回x,你可以从表中选择2个值S [a],S [b],例如&lt; x&lt;湾从这里,线性插值,你应该有一个公平的近似值
答案 4 :(得分:3)
如果您将fastSin中的返回值改为
return (1-P)*y + P*(y*abs(y))
并将y重写为(对于x> 0)
y = 4*x*(pi-x)/pi*pi
你可以看到y是选择的sin(x)
的抛物线一阶近似值,因此它通过(0,0),(pi / 2,1)和(pi,0)。 y*abs(y)
是一个“修正术语”,它也会通过这些点。
这种形式的整体近似函数保证函数(1-P)* y + P * y * y也将通过(0,0),(pi / 2,1)和(pi,0)。
一个问题是“如何选择P?”。就个人而言,我会选择在0,pi / 2间隔内产生最小RMS误差的P. (我不确定这个 P是如何被选中的)
尽量减少这个问题。 P给出
这可以重新安排并解决p
不确定这是否是P = 0.225。如果不是那么P的值可能是一个改进。 (除非选择P的其他值来保留其他一些无证件的财产)。
您可以通过添加额外的更正术语来提高准确性。给出类似return (1-a-b)*y + a y * abs(y) + b y * y * abs(y)
的表格。我会以与上面相同的方式找到a
和b
,这次给出了a
和b
中两个线性方程组的系统来解决,而不是一个p
中的等式。我不打算推导它,因为它的繁琐和乳胶图像的转换是痛苦的......;)
注意:在回答另一个问题时,我想到了P的另一个有效选择。 问题是使用反射将曲线延伸到(-pi,0)会在x = 0处的曲线中留下扭结。但是我怀疑我们可以选择P使得扭结变得平滑。 为此,在x = 0处取左右导数并确保它们相等。这给出了P的等式。
答案 5 :(得分:2)
怎么样?
x*(0.0174532925199433-8.650935142277599*10^-7*x^2)
表示deg和
x*(1-0.162716259904269*x^2)
对于rad分别是-45,45和-pi/4
,pi/4
?
答案 6 :(得分:1)
这(即fastsin函数)使用抛物线近似正弦函数。我怀疑它只适用于-π和+π之间的值。幸运的是,你可以继续增加或减去2π,直到你进入这个范围。 (编辑使用抛物线指定近似正弦函数的内容。)
答案 7 :(得分:1)