Cómo reducir un rango de números con un valor mínimo y máximo conocido

Resuelto user650271 asked hace 13 años • 8 respuestas

Así que estoy tratando de descubrir cómo tomar un rango de números y reducir los valores para que se ajusten a un rango. La razón para querer hacer esto es que estoy intentando dibujar elipses en un jpanel java swing. Quiero que la altura y el ancho de cada elipse estén en un rango de, digamos, 1-30. Tengo métodos que encuentran los valores mínimo y máximo de mi conjunto de datos, pero no tendré el mínimo y el máximo hasta el tiempo de ejecución. ¿Hay una forma fácil de hacer esto?

user650271 avatar Mar 14 '11 12:03 user650271
Aceptado

Supongamos que desea escalar un rango [min,max]a [a,b]. Estás buscando una función (continua) que satisfaga

f(min) = a
f(max) = b

En su caso, asería 1 y bsería 30, pero comencemos con algo más simple e intentemos mapearlo [min,max]en el rango [0,1].

Poner minen una función y sacar 0 se podría lograr con

f(x) = x - min   ===>   f(min) = min - min = 0

Entonces eso es casi lo que queremos. Pero incluirlo maxnos daría max - mincuando realmente 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. Entonces necesitamos hacer una traducción y una escala. Ahora, si queremos obtener valores arbitrarios de ay b, necesitamos algo un poco más complicado:

       (b-a)(x - min)
f(x) = --------------  + a
          max - min

Puedes comprobar que poner minpor xahora da a, y poner maxda b.

También puede notar que (b-a)/(max-min)hay un factor de escala entre el tamaño del nuevo rango y el tamaño del rango original. Entonces, en realidad, primero estamos traduciendo xpor -min, escalando al factor correcto y luego traduciéndolo nuevamente al nuevo valor mínimo de a.

irritate avatar Mar 14 '2011 05:03 irritate

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 entre 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]

Charles Clayton avatar Jul 28 '2015 21:07 Charles Clayton