Отображение числового диапазона на другой - PullRequest
54 голосов
/ 20 апреля 2011

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

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.

Я уверен, что это просто, я не могу думать прямо сейчас:)

Редактировать: мне просто нужны целые числа, без дробей или что-нибудь.

Ответы [ 5 ]

94 голосов
/ 20 апреля 2011

Давайте забудем математику и попытаемся решить это интуитивно.

Во-первых, если мы хотим отобразить входные числа в диапазоне [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))
22 голосов
/ 20 апреля 2011

Arduino имеет это встроенное как карта .

Пример:

/* 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;
}
11 голосов
/ 20 апреля 2011

Важным моментом здесь является целочисленное деление (которое включает в себя округление) в нужном месте. Ни один из ответов до сих пор не получил правильные скобки. Вот правильный путь:

int input_range = input_end - input_start;
int output_range = output_end - output_start;

output = (input - input_start)*output_range / input_range + output_start;
10 голосов
/ 27 марта 2017

формула

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.

е (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

Как вы можете видеть, теперь оно отображается правильно.

2 голосов
/ 20 апреля 2011
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...