【发布时间】:2012-12-08 18:47:51
【问题描述】:
#define PARTPERDEGREE 1
double mysinlut[PARTPERDEGREE * 90 + 1];
double mycoslut[PARTPERDEGREE * 90 + 1];
void MySinCosCreate()
{
int i;
double angle, angleinc;
// Each degree also divided into 10 parts
angleinc = (M_PI / 180) / PARTPERDEGREE;
for (i = 0, angle = 0.0; i <= (PARTPERDEGREE * 90 + 1); ++i, angle += angleinc)
{
mysinlut[i] = sin(angle);
}
angleinc = (M_PI / 180) / PARTPERDEGREE;
for (i = 0, angle = 0.0; i <= (PARTPERDEGREE * 90 + 1); ++i, angle += angleinc)
{
mycoslut[i] = cos(angle);
}
}
double MySin(double rad)
{
int ix;
int sign = 1;
double angleinc = (M_PI / 180) / PARTPERDEGREE;
if(rad > (M_PI / 2))
rad = M_PI / 2 - (rad - M_PI / 2);
if(rad < -(M_PI / 2))
rad = -M_PI / 2 - (rad + M_PI / 2);
if(rad < 0)
{
sign = -1;
rad *= -1;
}
ix = (rad * 180) / M_PI * PARTPERDEGREE;
double h = rad - ix*angleinc;
return sign*(mysinlut[ix] + h*mycoslut[ix]);
}
double MyCos(double rad)
{
int ix;
int sign = 1;
double angleinc = (M_PI / 180) / PARTPERDEGREE;
if(rad > M_PI / 2)
{
rad = M_PI / 2 - (rad - M_PI / 2);
sign = -1;
}
else if(rad < -(M_PI / 2))
{
rad = M_PI / 2 + (rad + M_PI / 2);
sign = -1;
}
else if(rad > -M_PI / 2 && rad < M_PI / 2)
{
rad = abs(rad);
sign = 1;
}
ix = (rad * 180) / M_PI * PARTPERDEGREE;
double h = rad - ix*angleinc;
return sign*(mycoslut[ix] - h*mysinlut[ix]);
}
double MyTan(double rad)
{
return MySin(rad) / MyCos(rad);
}
事实证明,使用除法计算 tan 比原来的 tan 函数更昂贵。
有没有什么方法可以在没有除法运算的情况下使用 sin/cos 查找表值计算 tan,因为在我的 MCU 上除法成本很高。
拥有tan LUT 并使用 tan/sin 或 tan/cos 提取结果是否更好,就像现在对 sin/cos 所做的那样?
【问题讨论】:
-
除法很昂贵 - 为什么不使用另一个 LUT 进行 tan 呢?您也可以只对 sin/cos 使用一个 LUT 而不是两个。对于这些 LUT 使用双精度可能没有意义 - 如果您对性能比对准确性更感兴趣,浮点数应该足够好。
-
@PaulR:首先没有逼近
sin (x+h) ≈ sin x + h*cos x和cos (x+h) ≈ cos x - h*sin x精度是不够的。其次,我不确定如何使用tan用 sin 或 cos LUT 来近似它。需要一些实际的帮助。 -
不过,如果除法太慢,为
tan建立一个查找表(那么你还需要sin和cos表吗?)。然后,您可以使用导数tan (x+h) ≈ tan x + h*(1 + tan² x)或线性插值double t = (rad * 180) / M_PI * PARTPERDEGREE; ix = (int)t; t -= ix; return t*mytanlut[ix+1] + (1-t)*mytanlut[ix];进行近似。线性插值通常会提供更好的近似值,但如果两个角度跨越π/2,则会产生垃圾,因为一个值将非常大且为正,另一个值非常大且为负[可能为±∞]。跨度> -
@DanielFischer:让我尝试使用这两种方法。实际上我还是需要 sin/cos 表,因为我在其他地方使用 sin/cos。一如既往,谢谢!
标签: c optimization