我在寫一段代碼時遇到了問題,這段代碼是在集成過程中圍繞一個角度進行的,並且是我正在處理的一個小模擬的一部分。所以基本上這個想法是通過確保它始終具有理智的價值來防止角度變大。我已經嘗試了三種不同的方法,我期望得到相同的結果。他們大部分時間都是這樣。但是前兩個在角度值環繞的地方產生了僞影。當我從角度值生成波形時,由於這些精度錯誤,我會得到不理想的結果。atan2f vs fmodf vs只是簡單的減法
所以第一個方法是這樣的(極限角度-8PI + 8PI範圍):
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;
那我在這裏失蹤?爲什麼其他兩種方法會產生精度錯誤?我希望他們都能產生相同的結果(我知道角度的範圍是不同的,但是當角度進一步傳遞到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; '不是'while(angle> limit)angle - = limit; '所以基本上如果'angle = 800000 * M_PI'你的最後一個方法不會把你的值放在範圍內。一個[mcve]可能很有用,輸入值是預期的,而使用'fmod'的「意想不到」(忘記atan2f' ATM) –
屏幕截圖看起來並不是在一臺機器上完成的,當你使用* double *而不是* float *。 –
該代碼只能在32位浮點支持的嵌入式目標上運行。 – Martin