If your number X falls between A and B, and you would like Y to fall between C and D, you can apply the following linear transform:

Y = (X-A)/(B-A) * (D-C) + C

That should give you what you want, although your question is a little ambiguous, since you could also map the interval in the reverse direction. Just watch out for division by zero and you should be OK.


Divide to get the ratio between the sizes of the two ranges, then subtract the starting value of your inital range, multiply by the ratio and add the starting value of your second range. In other words,

R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10

This evenly spreads the numbers from the first range in the second range.


It would be nice to have this functionality in the java.lang.Math class, as this is such a widely required function and is available in other languages. Here is a simple implementation:

final static double EPSILON = 1e-12;

public static double map(double valueCoord1,
        double startCoord1, double endCoord1,
        double startCoord2, double endCoord2) {

    if (Math.abs(endCoord1 - startCoord1) < EPSILON) {
        throw new ArithmeticException("/ 0");
    }

    double offset = startCoord2;
    double ratio = (endCoord2 - startCoord2) / (endCoord1 - startCoord1);
    return ratio * (valueCoord1 - startCoord1) + offset;
}

I am putting this code here as a reference for future myself and may be it will help someone.


As an aside, this is the same problem as the classic convert celcius to farenheit where you want to map a number range that equates 0 - 100 (C) to 32 - 212 (F).