Math - mapping numbers

China☆狼群 提交于 2019-11-27 10:11:18

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.

Konrad Rudolph

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).

Each unit interval on the first range takes up (d-c)/(b-a) "space" on the second range.

Pseudo:

var interval = (d-c)/(b-a)
for n = 0 to (b - a)
    print c + n*interval

How you handle the rounding is up to you.

int srcMin = 2, srcMax = 6;
int tgtMin = 10, tgtMax = 20;

int nb = srcMax - srcMin;
int range = tgtMax - tgtMin;
float rate = (float) range / (float) nb;

println(srcMin + " > " + tgtMin);
float stepF = tgtMin;
for (int i = 1; i < nb; i++)
{
  stepF += rate;
  println((srcMin + i) + " > " + (int) (stepF + 0.5) + " (" + stepF + ")");
}
println(srcMax + " > " + tgtMax);

With checks on divide by zero, of course.

In addition to @PeterAllenWebb answer, if you would like to reverse back the result use the following:

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

if your range from [a to b] and you want to map it in [c to d] where x is the value you want to map use this formula (linear mapping)

double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!