Я перевожу некоторый код на C ++ относительно PMP для контроля ориентации и использования части кода FLT_EPSILON
,
Код делает следующее:
while (angle > ((float)M_PI+FLT_EPSILON))
M_PI
это просто, но я не уверен, что с FLT_EPSILON
, Гугл сказал мне:
Это разница между 1 и наименьшей плавающей точкой
число типа float больше 1. Предполагается, что нет
больше чем 1E-5.
Однако другие источники заявляют такие ценности, как 1.192092896e-07F
,
Я не на 100% понимаю, почему он используется. Я подозреваю, что это связано с гранулярностью поплавка. Так что, если кто-то может прояснить, что он пытается делать в c ++, и если это касается javascript, то это было бы очень полезно.
Я не уверен, как JavaScript работает с внутренними вещами, такими как эти значения, поэтому помощь будет принята с благодарностью.
Как к сведению, код, который я перевожу, выглядит следующим образом (полученный из QGroundControl, это с открытым исходным кодом):
float limitAngleToPMPIf(float angle) {
if (angle > -20*M_PI && angle < 20 * M_PI) {
while (angle > ((float)M_PI + FLT_EPSILON)) {
angle -= 2.0f * (float)M_PI;
}
while (angle <= -((float)M_PI + FLT_EPSILON)) {
angle += 2.0f * (float)M_PI;
}
} else {
// Approximate
angle = fmodf(angle, (float)M_PI);
}
return angle;
}
— редактировать —
Просто понял, что fmodf не определен. По-видимому, это функция lib и выполняет следующие действия:
Функция fmod () вычисляет остаток с плавающей точкой от деления
х за у. Возвращаемое значение: x — n * y, где n — частное от x /
у, округляется от нуля до целого числа.
Этот код пытается сохранить angle
в интервале около нуля.
Тем не менее, управление углами таким образом является хлопотным и требует значительной осторожности. Если это не сопровождается документацией, объясняющей, что делается, почему, и различными ошибками и спецификациями, которые это делают, то это было сделано неправильно.
Для такого вида уменьшения угла невозможно точно сохранить накопленные изменения в течение длинной последовательности изменений, потому что M_PI
является лишь приближением к π. Следовательно, такого рода сокращения обычно полезны только для эстетического или интерфейсного эффекта. Например, при изменении некоторого угла его уменьшение может удерживать его от роста до точки, в которой могут быть большие скачки в результатах вычислений из-за квантования с плавающей запятой или других ошибок вычислений, которые могут раздражать зрителя. Таким образом, поддерживая угол в пределах интервала около нуля, дисплей выглядит хорошо, даже если он отличается от того, что реальная физика сделала бы в долгосрочной перспективе.
Выбор FLT_EPSILON
кажется произвольным. FLT_EPSILON
важно для представления тонкости float
формат. Однако по величине M_PI
ULP (самое прекрасное изменение) float
на самом деле 2*FLT_EPSILON
, Кроме того, JavaScript выполняет сложение с арифметикой двойной точности и FLT_EPSILON
не имеет особого значения в этом double
формат. Я подозреваю, что автор просто выбрал FLT_EPSILON
потому что это был удобный «маленький» номер. Я ожидаю, что код будет работать так же хорошо, как если бы angle > M_PI
было написано, без прикрас, и (float) M_PI
были изменены на M_PI
везде это появляется. (Добавление FLT_EPSILON
возможно, предполагалось добавить некоторый гистерезис в систему, чтобы он не часто переключался между значениями около π и значениями около –π. Тем не менее, критерий, который я предлагаю, angle > M_PI
Также включает в себя некоторые из того же эффекта, хотя и в меньшем количестве. Это может быть неочевидно для кого-то, неопытного с арифметикой с плавающей точкой.)
Кроме того, это выглядит как angle = fmodf(angle, (float) M_PI);
может быть ошибка, так как это уменьшение по модулю M_PI
скорее, чем 2*M_PI
, поэтому он добавит 180 ° к некоторым углам, что приведет к совершенно неправильному результату.
Возможно, что замена всего тела функции на return fmod(angle, 2*M_PI);
будет работать удовлетворительно.
Других решений пока нет …