Сопоставление числового диапазона с другим

математика никогда не была моей сильной стороной в школе :(

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

то, что это делает, это узнать пропорционально "как далеко в" входной диапазон ввода. Затем он применяет эту пропорцию к размеру выходного диапазона, чтобы узнать в абсолютном выражении, насколько далеко в выходном диапазоне должен быть выход. Затем он добавляет начало выходного диапазона, чтобы получить фактический выходной номер.