Asignar un rango numérico a otro


Las matemáticas nunca fueron mi fuerte en la escuela : (

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;

¿Cómo puedo convertir el valor de entrada al valor de salida correspondiente de ese rango?

Por ejemplo, un valor de entrada de "0" equivaldría a un valor de salida de "500", un valor de entrada de "254" equivaldría a un valor de salida de "5500". No puedo averiguar cómo calcular un valor de salida si un valor de entrada es decir 50 o 101.

Estoy seguro de que es simple, no puedo pensar en este momento:)

Editar: Solo necesito números enteros, no fracciones o algo así.

Author: Peter Mortensen, 2011-04-20

5 answers

Olvidemos las matemáticas y tratemos de resolver esto intuitivamente.

Primero, si queremos mapear los números de entrada en el rango [0, x] a rango de salida[0, y], solo necesitamos escalar en una cantidad apropiada. 0 va a 0, x va a y, y un número t irá a (y/x)*t.

Por lo tanto, vamos a reducir su problema al problema más simple anterior.

Un rango de entrada de [input_start, input_end] tiene input_end - input_start + 1 números. Por lo que es equivalente a un rango de [0, r], donde r = input_end - input_start.

Del mismo modo, el rango de salida es equivalente a [0, R], donde R = output_end - output_start.

Una entrada de input es equivalente a x = input - input_start. Esto, del primer párrafo se traducirá a y = (R/r)*x. Luego, podemos traducir el valor y al rango de salida original agregando output_start: output = output_start + y.

Esto nos da:

output = output_start + ((output_end - output_start) / (input_end - input_start)) * (input - input_start)

O, de otra manera:

/* 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)

Ahora, siendo esto C, y la división en C trunca, usted debe tratar de obtener una respuesta más precisa por calculando cosas en coma flotante:

double slope = 1.0 * (output_end - output_start) / (input_end - input_start)
output = output_start + slope * (input - input_start)

Si se quisiera ser aún más correcto, se haría un redondeo en lugar de truncamiento en el paso final. Puedes hacer esto escribiendo una simple función round:

#include <math.h>
double round(double d)
{
    return floor(d + 0.5);
}

Entonces:

output = output_start + round(slope * (input - input_start))
 66
Author: Alok Singhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 14:57:20

Arduino tiene esto incorporado como map .

Ejemplo:

/* 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);
}

También tiene la implementación en esa página:

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;
}
 19
Author: Dustin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 19:45:56

El punto crucial aquí es hacer la división entera (que incluye el redondeo) en el lugar correcto. Ninguna de las respuestas hasta ahora acertó con los paréntesis. Aquí está el camino correcto:

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

output = (input - input_start)*output_range / input_range + output_start;
 8
Author: Sven Marnach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 14:37:35

La fórmula es

F(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

Voy a conectar este post aquí: https://betterexplained.com/articles/rethinking-arithmetic-a-visual-guide / ya que me ayudó mucho al tratar de llegar a esto intuitivamente. Una vez que entiendas lo que está diciendo el post, es trivial llegar a estas fórmulas por tu cuenta. Tenga en cuenta que solía luchar con tales preguntas también. (No tengo afiliaciones - acaba de encontrar muy útil)

Digamos que tienes rango [input_start..input_end], comencemos por normalizarlo de tal manera que 0 es input_start, y 1 es input_end. esta es una técnica simple para hacer el problema más fácil.

¿Cómo hacemos eso? vamos, tendríamos que cambiar todo lo que queda por input_start cantidad, de modo que si entrada x pasa a ser input_start, debe dar cero.

Entonces, digamos que f(x) es la función que hace la conversión.

f(x) = x - input_start

Vamos a pruébalo:

f(input_start) = input_start - input_start = 0

Funciona para input_start.

En este punto, no funciona para input_end todavía, ya que no lo hemos escalado.

Vamos a reducirlo por la longitud del rango, entonces tendremos el valor más grande (input_end) asignado a uno.

f(x) = (x - input_start) / (input_end - input_start)

Ok, vamos a darle una oportunidad con input_end.

F (input_end) = (input_end - input_start) / (input_end - input_start) = 1

Impresionante, parece funcionar.

Bien, el siguiente paso, lo escalaremos al rango de salida. Es tan trivial como simplemente multiplicarse con el longitud real del rango de salida, como tal:

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start)

Ahora, en realidad, casi hemos terminado, solo tenemos que desplazarlo a la derecha para que 0 comience desde output_start.

f(x) = (x - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

Vamos a darle una oportunidad rápida.

f(input_start) = (input_start - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

Ves que la primera parte de la ecuación se multiplica por cero, cancelando así todo, dándote

f(input_start) = output_start

Intentemos input_end también.

f(input_end) = (input_end - input_start) / (input_end - input_start) * (output_end - output_start) + output_start

Que a su vez terminará como:

f(input_end) = output_end - output_start + output_start = output_end

Como puedes ver, ahora parece para ser mapeado correctamente.

 6
Author: Erti-Chris Eelmaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-27 11:20:45
output = ((input - input_start)/(input_end - input_start)) * (output_end - output_start) + output_start

Lo que eso hace es averiguar proporcionalmente "qué tan dentro" del rango de entrada está la entrada. Luego aplica esa proporción al tamaño del rango de salida para averiguar en términos absolutos qué tan lejos en el rango de salida debe estar la salida. Luego agrega el inicio del rango de salida para obtener el número de salida real.

 1
Author: QuantumMechanic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 14:25:31