В настоящее время я разрабатываю прошивку для медицинского устройства, в которой много сложных математических операций.Целевой процессор поддерживает операции с плавающей запятой аппаратно, но только float32
(он же single
).
Чтобы смоделировать поведение и доказать правильность моих формул и кода, я перенес соответствующую математическую частьиз встроенного ПО для инструментария GCC в Linux (gcc 6.3.0, libc6 2.24), дважды проверяя, что float32
используется повсеместно и что не используется переключатель компилятора, который может снизить точность или совместимость стандартов математических операций;Примечательно, что нет ни одного -ffast-math
или его друзей.
Теперь оказалось, что я получаю неожиданные результаты для небольшого набора входных параметров.Я разыскал проблему и пришел к выводу, что libm
вычисляет неверный результат для arctan
(если быть точным: atan2
) для очень небольшого набора входных параметров.
Например,, если у меня есть
#include <math.h>
#define C_RAD2DEG (57.29577951308f)
int main(void)
{
float f_Temp = C_RAD2DEG * atan2f(0.713114202f, 0.665558934f);
}
f_Temp
вычисляется как 46.9755516f
, где правильный результат будет 46.975548972f
.
Обратите внимание, что я в целом осведомлен о проблемахс различными типами данных с плавающей запятой, ошибками округления и т. п.
Однако мне кажется, что показанная выше ошибка слишком велика на порядок даже при низкой точности float32
, и, к сожалению,для последующих расчетов эта ошибка слишком велика.
Кроме того, проблема связана только с очень небольшим подмножеством возможных входных параметров для функции atan2
.
Может кто-нибудь пожалуйстакратко объясните, является ли это ошибкой в libm
или это просто из-за неточности float32
и большого количества последовательных операций, необходимых для вычисления atan2
?