基本上,我一直在尝试制作两个近似函数。在这两种情况下,我都输入了“x”和“y”组件(以处理那些讨厌的 n/0 和 0/0 条件),并且需要得到一个 Signed Char 输出。在 ATAN2 的情况下,它应该提供 +/-PI 的范围,在 ATAN 的情况下,范围应该是 +/- PI/2。
我花了整个昨天的时间试图把我的头包起来。在 excel 中玩耍以找到基于近似值的整体良好算法后:
X * (PI/4 + 0.273 * (1 - |X|)) * 128/PI // Scale factor at end to switch to char format
我想出了以下代码:
signed char nabsSC(signed char x)
{
if(x > 0)
return -x;
return x;
}
signed char signSC(signed char input, signed char ifZero = 0, signed char scaleFactor = 1)
{
if(input > 0)
{return scaleFactor;}
else if(input < 0)
{return -scaleFactor;}
else
{return ifZero;}
}
signed char divisionSC(signed char numerator, signed char denominator)
{
if(denominator == 0) // Error Condition
{return 0;}
else
{return numerator/denominator;}
}
//#######################################################################################
signed char atan2SC(signed char y, signed char x)
{
// @todo make clearer : the code was deduced through trial and error in excel with brute force... not the best reasoning in the world but hey ho
if((x == y) && (x == 0)) // Error Condition
{return 0;}
// Prepare for algorithm Choice
const signed char X = abs(x);
signed char Y = abs(y);
if(Y > 2)
{Y = (Y << 1) + 4;}
const signed char alpha1 = 43;
const signed char alpha2 = 11;
// Make Choice
if(X <= Y) // x/y Path
{
const signed char beta = 64;
const signed char a = divisionSC(x,y); // x/y
const signed char A = nabsSC(a); // -|x/y|
const signed char temp = a * (alpha1 + alpha2 * A); // (x/y) * (32 + ((0.273 * 128) / PI) * (1 - |x/y|)))
// Small angle approximation of ARCTAN(X)
if(y < 0) // Determine Quadrant
{return -(temp + beta);}
else
{return -(temp - beta);}
}
else // y/x Path
{
const signed char a = divisionSC(y,x); // y/x
const signed char A = nabsSC(a); // -|y/x|
const signed char temp = a * (alpha1 + alpha2 * A); // (y/x) * (32 + ((0.273 * 128) / PI) * (1 - |y/x|)))
// Small angle approximation of ARCTAN(X)
if(x < 0) // Determine Quadrant
{
Y = signSC(y, -127, 127); // Sign(y)*127, if undefined: use -127
return temp + Y;
}
else
{return temp;}
}
}
令我绝望的是,实现的错误高达 180 度,而且几乎无处不在。(在转换为有符号字符格式后,我将它与库中的 ATAN2F 进行了比较。)
我从这个网站得到了一般要点:http: //geekshavefeelings.com/posts/fixed-point-atan2
谁能告诉我哪里出错了?以及我应该如何在没有这些疯狂的情况下接近 ATAN 变体(应该更精确,因为它看起来超过一半的范围)。
我目前在 Windows 上使用 QT creator 4.8.1。这段特定代码的最终平台最终将是一个没有 FPU 的微控制器,ATAN 功能将是使用的主要功能之一。因此,具有合理误差的效率(ATAN2 为 +/-2 度,ATAN 为 +/-1 度。这些是目前的猜测,所以我可能会增加范围,但是,90 度绝对是不可接受的!)是目标的游戏。
提前感谢您的任何帮助!
编辑:为了澄清一下,ATAN2 和 ATAN 的输出输出到有符号的 char 值,但是这两种类型的范围是不同的范围。
ATAN2 应具有从 -128 (-PI) 到 127 (+PI - PI/128) 的范围。
ATAN 的范围从 -128 (-PI/2) 到 127 (+PI/2 - PI/256)。
因此,两者的输出值可以被认为是两种不同的数据类型。
很抱歉有任何混淆。
EDIT2:将隐式 int 数字显式转换为带符号的 char 常量。