Добавление ответа romkyns, помимо преобразования всех значений в удвоенные значения перед преобразованием во избежание переполнения, ваш код возвращает неверные результаты, когда нижние границы отличаются от 0, поскольку вы не корректируете значения соответствующим образом. Идея заключается в отображении диапазона [in_min, in_max] в диапазон [out_min, out_max], поэтому:
- f (in_min) = out_min
- f (in_max) = out_max
Пусть x будет значением для сопоставления. Алгоритм что-то вроде:
- Отображение диапазона [in_min, in_max] на [0, in_max - in_min]. Для этого вычтите in_min из x.
- Отображение диапазона [0, in_max - in_min] на [0, 1]. Для этого разделите x на (in_max - in_min).
- Отображение диапазона [0, 1] на [0, out_max - out_min]. Для этого умножьте x на (out_max - out_min).
- Отображение диапазона [0, out_max - out_min] на [out_min, out_max]. Для этого добавьте out_min к x.
Следующая реализация в C ++ делает это (я забуду значения по умолчанию, чтобы сделать код более понятным:
template <class I, class O>
O convertRatio(I x, I in_min, I in_max, O out_min, O out_max) {
const double t = ((double)x - (double)in_min) /
((double)in_max - (double)in_min);
const double res = t * ((double)out_max - (double)out_min) + out_min;
return O(res);
}
Обратите внимание, что я не взял абсолютное значение размеров диапазона. Это позволяет обратное отображение. Например, это позволяет сопоставить [-1.0, 1.0] с [3.0, 2.0], давая следующие результаты:
- коэффициент преобразования (-1,0, -1,0, 1,0, 3,0, 2,0) = 3,0
- convertRatio (-0,8, -1,0, 1,0, 3,0, 2,0) = 2,9
- convertRatio (0,8, -1,0, 1,0, 3,0, 2,0) = 2,1
- convertRatio (1,0, -1,0, 1,0, 3,0, 2,0) = 2,0
Единственное необходимое условие: in_min! = In_max (для предотвращения деления на ноль) и out_min! = Out_max (в противном случае все входы будут отображаться в одну точку). Чтобы избежать ошибок округления, старайтесь не использовать маленькие диапазоны.