Сопоставление числового диапазона с другим
математика никогда не была моей сильной стороной в школе :(
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.
Я уверен, что это просто, я не могу думать прямо сейчас :)
Изменить: I просто нужны целые числа, никаких дробей или чего-то еще.
5 ответов
давайте забудем математику и попробуем решить это интуитивно.
во-первых, если мы хотим отобразить входные номера в диапазоне [0
, x
] в выходной диапазон [0
, y
], нам просто нужно масштабировать на соответствующую сумму. 0 идет 0, x
идет y
, и пойдет (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)
если бы вы хотели быть еще более правильным, Вы бы сделали округление вместо усечения на последнем шаге. Вы можете сделать это, написав простой :
#include <math.h>
double round(double d)
{
return floor(d + 0.5);
}
затем:
output = output_start + round(slope * (input - input_start))
Arduino имеет этот встроенный as карта.
пример:
/* 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;
}
решающим моментом здесь является целочисленное деление (которое включает округление) в нужном месте. Ни один из ответов пока не дал правильных скобок. Вот правильный путь:
int input_range = input_end - input_start;
int output_range = output_end - output_start;
output = (input - input_start)*output_range / input_range + output_start;
формула
f (x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start
я подключу этот пост здесь:https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide/ поскольку это очень помогло мне, когда я пытался придумать это интуитивно. Как только вы поймете, что говорит post, тривиально придумывать эти формулы самостоятельно. Обратите внимание, что я использовал, чтобы боритесь И с такими вопросами. (У меня нет принадлежности - просто нашел это очень полезным)
скажите, что у вас есть диапазон [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
как вы можете видеть, теперь он, кажется, отображается правильно.
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start
то, что это делает, это узнать пропорционально "как далеко в" входной диапазон ввода. Затем он применяет эту пропорцию к размеру выходного диапазона, чтобы узнать в абсолютном выражении, насколько далеко в выходном диапазоне должен быть выход. Затем он добавляет начало выходного диапазона, чтобы получить фактический выходной номер.