Jak odwzorować liczby liniowo między a i b, aby przejść między c i d.
Oznacza to, że chcę, aby liczby od 2 do 6 odwzorowywały liczby od 10 do 20 ... ale potrzebuję uogólnionego przypadku.
Mój mózg jest usmażony.
Jak odwzorować liczby liniowo między a i b, aby przejść między c i d.
Oznacza to, że chcę, aby liczby od 2 do 6 odwzorowywały liczby od 10 do 20 ... ale potrzebuję uogólnionego przypadku.
Mój mózg jest usmażony.
Odpowiedzi:
Jeśli twoja liczba X mieści się między A i B, a chciałbyś, aby Y znajdował się między C i D, możesz zastosować następującą transformację liniową:
Y = (X-A)/(B-A) * (D-C) + C
To powinno dać ci to, czego chcesz, chociaż twoje pytanie jest trochę niejednoznaczne, ponieważ możesz również odwzorować interwał w odwrotnym kierunku. Uważaj tylko na dzielenie przez zero i powinno być OK.
Y=f(X)=m*X+b
gdzie m i b zostały wyznaczone jednocześnie z następujących dwóch równań ograniczających, które wynikają z podstawienia wartości X i Y w wymaganych punktach końcowych: C=m*A+b
orazD=m*B+b
X=A+(A-B)*t
udowodnić równość między tym podejściem a podejściem Petera. t jest zasadniczo niewymiarowaniem X. ( t=(X-A)/(A-B)
)
Podziel, aby uzyskać stosunek między rozmiarami dwóch zakresów, a następnie odejmij wartość początkową zakresu początkowego, pomnóż przez współczynnik i dodaj wartość początkową drugiego zakresu. Innymi słowy,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
Spowoduje to równomierne rozłożenie liczb z pierwszego zakresu w drugim zakresie.
Byłoby miło mieć tę funkcjonalność w java.lang.Math
klasie, ponieważ jest to bardzo wymagana funkcja i jest dostępna w innych językach. Oto prosta implementacja:
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;
}
Umieszczam ten kod tutaj jako odniesienie na przyszłość i może to komuś pomoże.
Na marginesie, jest to ten sam problem, co w klasycznej konwersji Celsjusza na Farenheita, w którym chcesz zmapować zakres liczb, który jest równy 0 - 100 (C) do 32 - 212 (F).
Każdy odstęp jednostkowy w pierwszym zakresie zajmuje (dc) / (ba) „spację” w drugim zakresie.
Rzekomy:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
Sposób obsługi zaokrąglania zależy od Ciebie.
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);
Oczywiście z kontrolą dzielenia przez zero.
jeśli twój zakres od [a do b] i chcesz go zmapować w [c do d], gdzie x jest wartością, którą chcesz odwzorować, użyj tego wzoru (mapowanie liniowe)
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)