Esta división ha sido aprobado por nuestros expertos así se garantiza la veracidad de nuestro post.
Solución:
Digamos que quieres escalar un rango [min,max]
para [a,b]
. Está buscando una función (continua) que satisfaga
f(min) = a
f(max) = b
En tu caso, a
sería 1 y b
serían 30, pero comencemos con algo más simple e intentemos mapear [min,max]
en el rango [0,1]
.
Poniendo min
en una función y salir 0 podría lograrse con
f(x) = x - min ===> f(min) = min - min = 0
Eso es casi lo que queremos. pero poniendo en max
nos daría max - min
cuando en realidad queremos 1. Así que tendremos que escalarlo:
x - min max - min
f(x) = --------- ===> f(min) = 0; f(max) = --------- = 1
max - min max - min
que es lo que queremos. Así que tenemos que hacer una traducción y una escala. Ahora bien, si en cambio queremos obtener valores arbitrarios de a
y b
necesitamos algo un poco más complicado:
(b-a)(x - min)
f(x) = -------------- + a
max - min
Puedes comprobar que poniendo en min
por x
ahora da a
y poniendo en max
da b
.
También puede notar que (b-a)/(max-min)
es un factor de escala entre el tamaño del nuevo rango y el tamaño del rango original. Así que realmente estamos primero traduciendo x
por -min
escalándolo al factor correcto y luego traduciéndolo de nuevo al nuevo valor mínimo de a
.
Espero que esto ayude.
Aquí hay algo de JavaScript para copiar y pegar fácilmente (esta es la respuesta de irritate):
function scaleBetween(unscaledNum, minAllowed, maxAllowed, min, max)
return (maxAllowed - minAllowed) * (unscaledNum - min) / (max - min) + minAllowed;
Aplicado así, escalando el rango de 10-50 a un rango de 0-100.
var unscaledNums = [10, 13, 25, 28, 43, 50];
var maxRange = Math.max.apply(Math, unscaledNums);
var minRange = Math.min.apply(Math, unscaledNums);
for (var i = 0; i < unscaledNums.length; i++)
var unscaled = unscaledNums[i];
var scaled = scaleBetween(unscaled, 0, 100, minRange, maxRange);
console.log(scaled.toFixed(2));
0,00, 18,37, 48,98, 55,10, 85,71, 100,00
Editar:
Sé que respondí esto hace mucho tiempo, pero aquí hay una función más limpia que uso ahora:
Array.prototype.scaleBetween = function(scaledMin, scaledMax)
var max = Math.max.apply(Math, this);
var min = Math.min.apply(Math, this);
return this.map(num => (scaledMax-scaledMin)*(num-min)/(max-min)+scaledMin);
Aplicado así:
[-4, 0, 5, 6, 9].scaleBetween(0, 100);
[0, 30.76923076923077, 69.23076923076923, 76.92307692307692, 100]
Para mayor comodidad, aquí está el algoritmo de Irritate en formato Java. Agregue verificación de errores, manejo de excepciones y ajuste según sea necesario.
public class Algorithms
public static double scale(final double valueIn, final double baseMin, final double baseMax, final double limitMin, final double limitMax)
return ((limitMax - limitMin) * (valueIn - baseMin) / (baseMax - baseMin)) + limitMin;
Ensayador:
final double baseMin = 0.0;
final double baseMax = 360.0;
final double limitMin = 90.0;
final double limitMax = 270.0;
double valueIn = 0;
System.out.println(Algorithms.scale(valueIn, baseMin, baseMax, limitMin, limitMax));
valueIn = 360;
System.out.println(Algorithms.scale(valueIn, baseMin, baseMax, limitMin, limitMax));
valueIn = 180;
System.out.println(Algorithms.scale(valueIn, baseMin, baseMax, limitMin, limitMax));
90.0
270.0
180.0