Вычислить atan2 без std-функций или C99

Я вычисляю углы с 3-осевым акселерометром, но у моего компилятора нет функции atan или atan2. Он имеет зарезервированный слот памяти, но он вызывает функцию, которую я не могу найти ни в каких файлах.

Мой компилятор Keil μVision 4 работает с компилятором ARMCC. Компиляции имеют файл math.h, но функция extern и не существует:

extern _ARMABI double atan2(double /*y*/, double /*x*/); 

Есть ли lib или функция, которую я могу включить, которая выполняет функцию arctan? Или есть альтернативная функция для вычисления углов с акселерометра? Мне нужна полная 3-осевая калибровка углов.

Изменить: я надеялся избежать таблицы, полной предварительно рассчитанных значений.

Его не очень сложно реализовать собственный arctan2 . Преобразуйте arctan2 в arctan используя эту формулу. И вы можете рассчитать arctan используя эту бесконечную серию . Если вы суммируете достаточное количество членов этого бесконечного ряда, вы получите очень близкое к тому, что делает функция библиотеки arctan2 .

Вот одна аналогичная реализация для exp() которую вы можете использовать в качестве ссылки.

Следующий код использует рациональную аппроксимацию для получения арктангенса, нормированного на интервале [0 1) (вы можете умножить результат на Pi / 2, чтобы получить реальную арктангенс)

normalized_atan (x) ~ (bx + x ^ 2) / (1 + 2 bx + x ^ 2)

где b = 0,596227

Максимальная погрешность 0,1620º

 #include  #include  // Approximates atan(x) normalized to the [-1,1] range // with a maximum error of 0.1620 degrees. float normalized_atan( float x ) { static const uint32_t sign_mask = 0x80000000; static const float b = 0.596227f; // Extract the sign bit uint32_t ux_s = sign_mask & (uint32_t &)x; // Calculate the arctangent in the first quadrant float bx_a = ::fabs( b * x ); float num = bx_a + x * x; float atan_1q = num / ( 1.f + bx_a + num ); // Restore the sign bit uint32_t atan_2q = ux_s | (uint32_t &)atan_1q; return (float &)atan_2q; } // Approximates atan2(y, x) normalized to the [0,4) range // with a maximum error of 0.1620 degrees float normalized_atan2( float y, float x ) { static const uint32_t sign_mask = 0x80000000; static const float b = 0.596227f; // Extract the sign bits uint32_t ux_s = sign_mask & (uint32_t &)x; uint32_t uy_s = sign_mask & (uint32_t &)y; // Determine the quadrant offset float q = (float)( ( ~ux_s & uy_s ) >> 29 | ux_s >> 30 ); // Calculate the arctangent in the first quadrant float bxy_a = ::fabs( b * x * y ); float num = bxy_a + y * y; float atan_1q = num / ( x * x + bxy_a + num ); // Translate it to the proper quadrant uint32_t uatan_2q = (ux_s ^ uy_s) | (uint32_t &)atan_1q; return q + (float &)uatan_2q; } 

Если вам нужна более высокая точность, существует рациональная функция 3-го порядка:

normalized_atan (x) ~ (cx + x ^ 2 + x ^ 3) / (1 + (c + 1) x + (c + 1) x ^ 2 + x ^ 3)

где c = (1 + sqrt (17)) / 8

который имеет максимальную погрешность аппроксимации 0,00811º

Здесь есть реализация с открытым исходным кодом.

Фактические реализации математических функций (или заглушек для HWFPU, если таковые существуют) должны быть в libm. С GCC это указывается передачей -lm компилятору, но я не знаю, как это делается с вашими конкретными инструментами.