Math - mapping numbers

How do I map numbers, linearly, between a and b to go between c and d.

That is, I want numbers between 2 and 6 to map to numbers between 10 and 20... but I need the generalized case.

My brain is fried.

72276 次浏览

除以得到两个范围大小之间的比率,然后减去初始范围的起始值,乘以比率,再加上第二个范围的起始值。换句话说,

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

这将使第一个范围中的数字在第二个范围中均匀地分布。

如果你的数字 X 在 A 和 B 之间,你希望 Y 在 C 和 D 之间,你可以应用下面的线性变换:

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

这应该会得到您想要的结果,尽管您的问题有点模棱两可,因为您还可以将间隔映射到相反的方向。只要小心零除法,你就会没事的。

第一个范围上的每个单位间隔占用第二个范围上的(d-c)/(b-a)“空间”。

修多:

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

你怎么处理四舍五入取决于你。

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

当然还有除以零的支票。

顺便说一句,这个问题和经典的将 Celcius 转换为 farenheit 的问题是一样的,在这个问题中,您需要映射一个等于0-100(C)到32-212(F)的数值范围。

除了@PeterAllenWebb 的回答,如果你想把结果反过来使用以下方法:

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

如果在 java.lang.Math类中有这个功能就好了,因为这是一个广泛需要的功能,并且可以在其他语言中使用。 下面是一个简单的实现:

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.

如果你的范围是从[ a 到 b ] ,你想把它映射到[ c 到 d ] ,其中 x 是你想映射的值 使用这个公式(线性映射)

double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)

Https://rosettacode.org/wiki/map_range

[a1, a2] => [b1, b2]


if s in range of [a1, a2]


then t which will be in range of [b1, b2]


t= b1 + ((s- a1) * (b2-b1))/ (a2-a1)

其中 X是从 A-B映射到 C-D的数字,而 为什么是结果: 采用线性插值公式,lerp (B) = + ( * (B-)) ,然后用 CD代替 B,得到 B1 = C + ( * (D-C))。然后,用(B7-B8)/(B9-B8)代替 ,得到 B1 = C + (((B7-B8)/(B9-B8)) * (D-C))。这是一个不错的 map 函数,但它可以被简化。取(D-C)部分,将其放入股息中,得到 B1 = C + (((B7-B8) * (D-C))/(B9-B8))。这给了我们另一个可以简化的部分,(B7-B8) * (D-C) ,等同于(B7 * D)-(B7 * C)-(B8 * D) + (B8 * C)。放进去,就得到了 B1 = C + (((B7 * D)-(B7 * C)-(B8 * D) + (B8 * C))/(B9-B8))。接下来需要做的事情是添加 + C位。要做到这一点,你把 C乘以(B9 * C)得到((B9 * C)-(B8 * C)) ,然后把它移到红利中得到 B1 = (((B7 * D)-(B7 * C)-(B8 * D) + (B8 * C) + (B9 * C)-(B8 * C))/(B9-B8))。这是多余的,包含 a + (B8 * C)和 a-(B8 * C) ,它们相互抵消。除去它们,你得到的最终结果是: B1 = ((B7 * D)-(B7 * C)-(B8 * D) + (B9 * C))/(B9-B8)

TL; DR: 标准映射函数 为什么 = C + (((X-A)/(B-A)) * (D-C))可简化为 为什么 = ((X * D)-(X * C)-(A * D) + (B * C))/(B-A)