c – 这个余弦16位功能究竟在做什么?
作者:互联网
我想我在审查其他人的代码方面相当不错……但我不知所措.这来自Doom3 Math库.我相信自从Quake 1以来,这可能存在于GPL中.请注意,这确实引用了math.h.我猜有一些方法,这实际上计算余弦……但我无法弄明白.谁解释一下?
ID_INLINE float idMath::Cos16( float a ) {
float s, d;
if ( ( a < 0.0f ) || ( a >= TWO_PI ) ) {
a -= floorf( a / TWO_PI ) * TWO_PI;
}
#if 1
if ( a < PI ) {
if ( a > HALF_PI ) {
a = PI - a;
d = -1.0f;
} else {
d = 1.0f;
}
} else {
if ( a > PI + HALF_PI ) {
a = a - TWO_PI;
d = 1.0f;
} else {
a = PI - a;
d = -1.0f;
}
}
#else
a = PI - a;
if ( fabs( a ) >= HALF_PI ) {
a = ( ( a < 0.0f ) ? -PI : PI ) - a;
d = 1.0f;
} else {
d = -1.0f;
}
#endif
s = a * a;
return d * ( ( ( ( ( -2.605e-07f * s + 2.47609e-05f ) * s - 1.3888397e-03f ) * s + 4.16666418e-02f ) * s - 4.999999963e-01f ) * s + 1.0f );
}
解决方法:
所有有条件的东西看起来都像是将角度折叠到一个象限(或者可能是八分圆,我不能打算弄清楚…;)),并记录校正因子(d).
最后一行是执行某种10阶多项式逼近(可能是Taylor或Chebyshev?).*但它只适用于偶数幂,因为cos是偶函数.它也使用Horner’s method来避免多次直接计算大功率.
然后使用d重新应用正确的符号.
*要查看这是“非常”准确,请尝试在Octave中运行以下代码(您可以在线完成,例如here):
% One quadrant
a = (-pi/2):0.1:(+pi/2);
% Exact result
y_exact = cos(a);
% Our approximation
s = a .* a;
y_approx = (((((-2.605e-07 .* s + 2.47609e-05) .* s - 1.3888397e-03) .* s + 4.16666418e-02) .* s - 4.999999963e-01) .* s + 1);
% Plot
hold on
plot(a, y_exact, 'b')
plot(a, y_approx, 'r')
标签:c,trigonometry 来源: https://codeday.me/bug/20190901/1781984.html