Отображение числового диапазона на другой
Математика никогда не была моим сильным костюмом в школе: (
int input_start = 0; // The lowest number of the range input.
int input_end = 254; // The lowest number of the range input.
int output_start = 500; // The lowest number of the range output.
int output_end = 5500; // The largest number of the range ouput.
int input = 127; // Input value.
int output = 0;
Как преобразовать входное значение в соответствующее выходное значение этого диапазона?
Например, входное значение "0" будет равным выходному значению "500", входное значение "254" будет равно выходному значению "5500". Я не могу понять, как вычислить выходное значение, если входное значение имеет значение 50 или 101.
Я уверен, что это просто, я не могу сейчас думать:)
Изменить: мне просто нужны целые числа, никакие доли или что-то еще.
Ответы
Ответ 1
Забудьте о математике и попытайтесь решить эту проблему интуитивно.
Во-первых, если мы хотим отобразить номера ввода в диапазоне [ 0
, x
] для вывода диапазона [0
, y
], нам просто нужно масштабировать соответствующую сумму. 0 переходит в 0, x
переходит в y
, а число t
переходит в (y/x)*t
.
Итак, позвольте мне свести вашу проблему к вышеуказанной более простой проблеме.
Входной диапазон [ input_start
, input_end
] имеет input_end - input_start + 1
номера. Таким образом, это эквивалентно диапазону [0
, r
], где r = input_end - input_start
.
Аналогично, выходной диапазон эквивалентен [ 0
, r
], где R = output_end - output_start
.
Ввод input
эквивалентен x = input - input_start
. Это, начиная с первого абзаца, будет переведено на y = (R/r)*x
. Затем мы можем перевести значение y
обратно в исходный выходной диапазон, добавив output_start
: output = output_start + y
.
Это дает нам:
output = output_start + ((output_end - output_start) / (input_end - input_start)) * (input - input_start)
Или, иначе:
/* Note, "slope" below is a constant for given numbers, so if you are calculating
a lot of output values, it makes sense to calculate it once. It also makes
understanding the code easier */
slope = (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)
Теперь, когда это C и деление на C усекает, вы должны попытаться получить более точный ответ, вычислив вещи в плавающей точке:
double slope = 1.0 * (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)
Если бы вы хотели быть более корректным, вы бы сделали округление вместо усечения на последнем шаге. Вы можете сделать это, написав простую функцию round
:
#include <math.h>
double round(double d)
{
return floor(d + 0.5);
}
Тогда:
output = output_start + round(slope * (input - input_start))
Ответ 2
Arduino имеет встроенный модуль map.
Пример:
/* Map an analog value to 8 bits (0 to 255) */
void setup() {}
void loop()
{
int val = analogRead(0);
val = map(val, 0, 1023, 0, 255);
analogWrite(9, val);
}
Он также имеет реализацию на этой странице:
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
Ответ 3
Решающим моментом здесь является целочисленное деление (которое включает округление) в нужном месте. Ни один из ответов до сих пор не получил правильных круглых скобок. Вот правильный путь:
int input_range = input_end - input_start;
int output_range = output_end - output_start;
output = (input - input_start)*output_range / input_range + output_start;
Ответ 4
формула
f (x) = (x - input_start)/(input_end - input_start) * (output_end - output_start) + output_start
Я подключу этот пост здесь: https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/, поскольку он очень помог мне, пытаясь придумать это интуитивно. Как только вы поймете, что говорит пост, тривиально придумать эти формулы самостоятельно. Заметьте, что я тоже занимался такими вопросами. (У меня нет веток - я просто нашел это очень полезным)
скажем, у вас есть диапазон [input_start..input_end]
, пусть начнется с нормализации его так, что 0 - input_start
, а 1 - input_end
. это простой способ облегчить задачу.
Как мы это делаем? мы должны будем сдвинуть все, оставшееся на величину input_start, так что если вход x будет input_start
, он должен дать нуль.
так что пусть f(x)
- это функция, которая выполняет преобразование.
f(x) = x - input_start
пусть попробует:
f(input_start) = input_start - input_start = 0
работает для input_start
.
на данный момент он еще не работает для input_end
, так как мы не масштабировали его.
пусть просто уменьшит его на длину диапазона, тогда мы получим самое большое значение (input_end), сопоставленное одному.
f(x) = (x - input_start) / (input_end - input_start)
хорошо, давайте попробуем с input_end
.
f (input_end) = (input_end - input_start)/(input_end - input_start) = 1
удивительный, кажется, работает.
хорошо, следующий шаг, мы на самом деле масштабируем его до диапазона вывода. Это так же тривиально, как просто умножение на фактическую длину выходного диапазона, как таковое:
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start)
теперь, фактически, мы почти закончили, нам просто нужно сдвинуть его вправо, чтобы 0 начиналось с output_start.
f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
пусть быстро попробует.
f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
вы видите, что первая часть уравнения в значительной степени умножается на ноль, тем самым отменяя все, предоставляя вам
f(input_start) = output_start
попробуйте также input_end
.
f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
который, в свою очередь, будет следующим:
f(input_end) = output_end - output_start + output_start = output_end
как вы можете видеть, теперь это выглядит правильно.
Ответ 5
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start
Что это значит, так это выяснить "насколько далеко" входной диапазон ввода. Затем он применяет эту пропорцию к размеру выходного диапазона, чтобы в абсолютном выражении узнать, насколько далеко должен быть выходной выход. Затем он добавляет начало выходного диапазона для получения фактического номера выхода.