У меня есть два метода интерполяции, которые я использую в некоторых своих программах...
__forceinline double InterpolateDouble(double dOldVal, double dOldMin, double dOldMax, double dNewMin, double dNewMax)
{
return (((dOldVal - dOldMin) * (dNewMax - dNewMin)) / (dOldMax - dOldMin)) + dNewMin;
}
__forceinline int InterpolateInteger(int nOldVal, int nOldMin, int nOldMax, int nNewMin, int nNewMax)
{
return (int)InterpolateDouble((double)nOldVal, (double)nOldMin, (double)nOldMax, (double)nNewMin, (double)nNewMax);
}
Метод InterpolateInteger()
просто вызывает метод InterpolateDouble()
для поддержания некоторой дробной точности. Является ли преобразование из целого числа удвоенным, и есть ли способ получить точный результат, используя только целые числа (без кастингов)?
Существует риск переполнения при умножении перед делением, поскольку ваш код здесь. Вы должны проверить возможные значения ваших входов, в дополнение к возможным промежуточным вычислениям умножения в коде, чтобы определить, будет ли тип int всегда достаточным для расчета. Усечение произойдет с целым делением, но если вы хотите получить целочисленный результат, ожидаемый. Преобразование из int в double является тривиальным с точки зрения процессора, так как перед вычислением перед ним стоит 0.
Если вы после максимальной оптимизации и точки интерполяции зафиксированы, вы можете использовать следующее целочисленное выражение:
(dOldVal * dNewDelta + dNewMin * dOldDelta - dOldMin * dNewDelta) / dOldDelta
которая имеет вид (A * X + B)/C
, где A
, B
и C
- три предварительно вычисленные целочисленные константы. Это даст точные целочисленные ответы.
Альтернативно, используйте A * X + B
с предварительно рассчитанными коэффициентами с двойной точностью, но стратегия округления должна быть тщательно скорректирована.
Еще одна возможность состоит в том, чтобы перемасштабировать и обогнуть коэффициенты A
и B
с использованием силы 2, давая быструю безделевую целочисленную формулу формы
(A * X + B) >> p
(стратегия округления также деликатна).
Это не преобразование из int в double, о котором вы должны беспокоиться. Это преобразование (усечение) обратно из double в int после завершения работы. Рассмотрим интерполяцию [0, 500] на [0, 1]. В этом случае, как только вы выполните интерполяцию double, число будет 1 выход для 500 входных сигналов и меньше единицы для ввода 0-499. Таким образом, ввод 0-499 приведет к выходу 0 после усечения, а 500 приведет к 1.