私は統合中に角度を囲むように書いたコードに問題があり、私が取り組んでいる小さなシミュレーションの一部です。ですから、基本的には、角度が大きくなるのを防ぐには、それが常に正当な価値を持っていることを確認することです。私は3つの異なるアプローチを試みましたが、私は同じ結果を期待しています。そして、ほとんどの時間彼らはします。しかし、最初の2つは、アングル値がラップアラウンドするポイントの周りにアーチファクトを与えます。私が角度値から波形を生成すると、これらの精度誤差のために望ましくない結果が得られます。atan2f対fmodf対公正な減算
だから、最初のアプローチは、この(-8PI + 8PI範囲に限界角度)のようなものです:
:の![enter image description here](https://i.stack.imgur.com/U92oG.jpg)
第二のアプローチ:これは、このように見えるアーティファクトを作成
self->state.angle = atan2f(sinf(angle/8), cosf(angle/8)) * 8;
self->state.angle = fmodf(angle, (float)(2.f * M_PI * 8))
は、しかし、私はちょうどこのようにそれを行う場合:
float limit = (8 * 2 * M_PI);
if(angle > limit) angle -= limit;
if(angle < 0) angle += limit;
self->state.angle = a;
だから私はここで何をしないのですか?なぜ他の2つの方法で精度誤差が生じるのでしょうか?私はそれらのすべてが同じ結果を生み出すことを期待するでしょう(私は角度の範囲が異なっていることを知っていますが、角度がさらにsin関数に渡されると、結果は同じになると思います)。
編集:小さなテスト
// g++ -o test test.cc -lm && ./test
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
int main(int argc, char **argv){
float a1 = 0;
float a2 = 0;
float a3 = 0;
float dt = 1.f/7500.f;
for(float t = -4.f * M_PI; t < (4.f * M_PI); t+=dt){
a1 += dt;
a2 += dt;
a3 += dt;
float b1 = a1;
if(b1 > 2.f * M_PI) b1 -= 2.f * M_PI;
if(b1 < 0.f) b1 += 2.f * M_PI;
float b2 = atan2f(sinf(a2), cosf(a2));
float b3 = fmodf(a3, 2 * M_PI);
float x1 = sinf(b1);
float x2 = sinf(b2);
float x3 = sinf(b3);
if((x1 * x2 * x3) > 1e-9){
printf("%f: x[%f %f %f],\tx1-x2:%f x1-x3:%f x2-x3:%f]\n", t, x1, x2, x3, (x1 - x2) * 1e9, (x1 - x3) * 1e9, (x2 - x3) * 1e9);
}
}
return 0;
}
出力:
-9.421306: x[0.001565 0.001565 0.001565], x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.421172: x[0.001431 0.001431 0.001431], x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.421039: x[0.001298 0.001298 0.001298], x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.420905: x[0.001165 0.001165 0.001165], x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-9.420772: x[0.001032 0.001032 0.001032], x1-x2:0.000000 x1-x3:0.000000 x2-x3:0.000000]
-6.275573: x[0.001037 0.001037 0.001037], x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275439: x[0.001171 0.001171 0.001171], x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275306: x[0.001304 0.001304 0.001304], x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275172: x[0.001438 0.001438 0.001438], x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.275039: x[0.001571 0.001571 0.001571], x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.274905: x[0.001705 0.001705 0.001705], x1-x2:0.000000 x1-x3:174.855813 x2-x3:174.855813]
-6.274772: x[0.001838 0.001838 0.001838], x1-x2:0.116415 x1-x3:174.855813 x2-x3:174.739398]
'if(angle> limit)angle - = limit; 'not 'であるwhile(angle> limit)angle - = limit; 'したがって、' angle = 800000 * M_PI'の場合、最後のメソッドは値を範囲に入れません。 amcveは、入力値、期待値、および "予期しない" fmod(atan2f' ATMを忘れる)を使用すると便利です。 –
スクリーンショットは、あなたが苦しんでいるマシン* float *の代わりに* double *を使用してください。 –
このコードは、32ビット浮動小数点サポートのみの埋め込みターゲットで実行されます。 – Martin