Как поместить число с точкой в диапазон?
Представим, что у нас есть счетчик оборотов в градусах (от 0 до 360) и изменение значение текущего положения может задаваться извне (например, повернуть на +98.75 или -217.112 градусов), причем несколько изменений могут приходить подряд. Т.о. положение может принимать значения в широком диапазоне, от -999.(9) до 999.(9) (или даже больше). Положение надо вывести в интерфейс, и для удобства, надо его преобразовать в значение в диапазоне от 0.0 до 360.
Вопрос - как можно просто и лаконично привести число с точкой (значения от -999.(9) до 999.(9)) привести к диапазону 0..359.(9). То есть нужен некий аналог остатка от целочисленного деления, но для числа с точкой.
Пример неоптимального решения:
if x >= 0 then
newFloat := Frac(x / 360) * 360
else
newFloat := (1 - Frac(x / 360)) * 360;
Как это можно записать проще и короче?
Ответы (2 шт):
Один из возможных вариантов - двойное использование FMod. Код получается следующим (результат FMod будет иметь знак первого аргумента, поэтому приходится делать двойное приведение диапазона):
newFloat := FMod(FMod(x, 360) + 360, 360);
Функция FMod появилась в Delphi XE8, и выглядит вот так и находится в System.Math:
// FMod returns the remainder of ANumerator / ADenominator
// (like mod in integers) with the same sign as ANumerator
function FMod(const ANumerator, ADenominator: Single): Single;
begin
Result := ANumerator - Trunc(ANumerator / ADenominator) * ADenominator;
end;
Более компактный вариант, в котором мы просто прибавляем 360 после проверки знака:
newFloat := FMod(x, 360) + IfThen(x < 0, 360);
Прим.: ф-я IfThen отмечена как inline, т.е. она почти наверняка будет выполнена "на месте".