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í.
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))
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;
}
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;
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.
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.
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