我在写一段代码时遇到了问题,这段代码是在集成过程中围绕一个角度进行的,并且是我正在处理的一个小模拟的一部分。所以基本上这个想法是通过确保它始终具有理智的价值来防止角度变大。我已经尝试了三种不同的方法,我期望得到相同的结果。他们大部分时间都是这样。但是前两个在角度值环绕的地方产生了伪影。当我从角度值生成波形时,由于这些精度错误,我会得到不理想的结果。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