基本的に、私は 2 つの近似関数を作成しようとしています。どちらの場合も、「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 度もの誤差があり、その間のほぼすべての場所にも誤差があります。(signed char 形式に変換した後、ライブラリの ATAN2F と比較しました。)
私はこのウェブサイトから一般的な要点を得ました: http://geekshavefeelings.com/posts/fixed-point-atan2
どこが間違っているのか誰か教えてもらえますか? そして、この狂気のない ATAN バリアント (範囲の半分以上を見ているため、より正確なはずです) にどのようにアプローチする必要がありますか。
現在、WindowsでQTクリエーター4.8.1を使用しています。この特定のコードのエンド プラットフォームは、最終的には FPU のないマイクロコントローラーになり、ATAN 機能は使用される主要な機能の 1 つになります。そのため、妥当な誤差 (ATAN2 で +/-2 度、ATAN で +/-1 度。これらは現時点では推測であるため、範囲を広げる可能性がありますが、90 度は絶対に受け入れられません!) を伴う効率が目標です。ゲームの。
事前にすべての助けに感謝します!
編集: 明確にするために、ATAN2 と ATAN の出力は符号付きの char 値に出力されますが、2 つの型の範囲は異なる範囲です。
ATAN2 の範囲は -128 (-PI) から 127 (+PI - PI/128) です。
ATAN の範囲は -128 (-PI/2) から 127 (+PI/2 - PI/256) です。
そのため、2 つの出力値は 2 つの異なるデータ型と見なすことができます。
混乱して申し訳ありません。
EDIT2: 暗黙的な int 数値を明示的に signed char 定数に変換しました。