我该如何将介于a和b之间的数字进行线性映射,使它们落在c和d之间。
也就是说,我希望2到6之间的数字映射到10到20之间...但我需要一个通用的方法。
我的脑子已经崩溃了。
我该如何将介于a和b之间的数字进行线性映射,使它们落在c和d之间。
也就是说,我希望2到6之间的数字映射到10到20之间...但我需要一个通用的方法。
我的脑子已经崩溃了。
如果你的数字X落在区间A和B之间,并且你希望数字Y落在区间C和D之间,那么你可以应用以下线性变换:
Y = (X-A)/(B-A) * (D-C) + C
这应该可以满足您的需求,尽管您的问题有点模糊,因为您也可以将区间映射到相反的方向。只要注意避免除以零,您就应该没问题。
Y=f(X)=m*X+b
,其中 m 和 b 是同时从以下两个约束方程中确定的,这些方程是通过在所需端点处替换 X 和 Y 的值得出的:C=m*A+b
和 D=m*B+b
。 - Chris ChiassonX=A+(A-B)*t
来证明这种方法与Peter的方法的等价性。 t 本质上是X的无量纲化表示。(t=(X-A)/(A-B)
) - Chris Chiasson将两个范围的大小取比率,然后减去您初始范围的起始值,乘以比率,再加上您第二个范围的起始值。换句话说,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
这将在第二个范围内均匀分布来自第一个范围的数字。希望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;
}
我把这段代码放在这里,作为以后参考的依据,或许也能帮助其他人。
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)
reverseX = (B-A)*(Y-C)/(D-C) + A
如果你的范围是[a到b],并且你想要将其映射到[c到d],其中x是你想要映射的值,使用这个公式(线性映射)
double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)
其中X是从A-B映射到C-D的数字,而Y是结果: 采用线性插值公式,lerp(a,b,m)=a+(m*(b-a)),并将C和D放在a和b的位置上得到Y=C+(m*(D-C))。然后,将(X-A)/(B-A)代替m,得到Y=C+(((X-A)/(B-A))*(D-C))。这是一个可以接受的映射函数,但可以简化。将(D-C)部分放入被除数中,得到Y=C+(((X-A)*(D-C))/(B-A))。这给我们另一个可以简化的部分,(X-A)*(D-C),它等于(X*D)-(X*C)-(A*D)+(A*C)。将其代入,你会得到Y=C+(((X*D)-(X*C)-(A*D)+(A*C))/(B-A))。下一步需要做的是添加+C位。为此,你需要将C乘以(B-A),得到((B*C)-(A*C)),并将其移入被除数中,得到Y=(((X*D)-(X*C)-(A*D)+(A*C)+(B*C)-(A*C))/(B-A))。这是冗余的,包含一个+(A*C)和一个-(A*C),它们相互抵消。删除它们,你会得到一个最终结果:Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
简而言之:标准的映射函数,Y=C+(((X-A)/(B-A))*(D-C)),可以简化为Y=((X*D)-(X*C)-(A*D)+(B*C))/(B-A)
第一个范围上的每个单位区间在第二个范围上占据了(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);
当然要检查除以零的情况。