Come faccio a mappare i numeri, linearmente, tra aeb per andare tra c e d.
Cioè, voglio che i numeri tra 2 e 6 vengano mappati su numeri tra 10 e 20 ... ma ho bisogno del caso generalizzato.
Il mio cervello è fritto.
Come faccio a mappare i numeri, linearmente, tra aeb per andare tra c e d.
Cioè, voglio che i numeri tra 2 e 6 vengano mappati su numeri tra 10 e 20 ... ma ho bisogno del caso generalizzato.
Il mio cervello è fritto.
Risposte:
Se il tuo numero X è compreso tra A e B e desideri che Y sia compreso tra C e D, puoi applicare la seguente trasformazione lineare:
Y = (X-A)/(B-A) * (D-C) + C
Questo dovrebbe darti quello che vuoi, anche se la tua domanda è un po 'ambigua, poiché potresti anche mappare l'intervallo nella direzione opposta. Fai attenzione alla divisione per zero e dovresti stare bene.
Y=f(X)=m*X+b
, dove m e b sono stati determinati simultaneamente dalle seguenti due equazioni dei vincoli che risultano dalla sostituzione dei valori di X e Y agli estremi richiesti: C=m*A+b
eD=m*B+b
X=A+(A-B)*t
per dimostrare l'uguaglianza tra questo approccio e quello di Peter. È essenzialmente una non dimensionalizzazione di X. ( t=(X-A)/(A-B)
)
Dividi per ottenere il rapporto tra le dimensioni dei due intervalli, quindi sottrai il valore iniziale dell'intervallo iniziale, moltiplicalo per il rapporto e aggiungi il valore iniziale del secondo intervallo. In altre parole,
R = (20 - 10) / (6 - 2)
y = (x - 2) * R + 10
Questo distribuisce uniformemente i numeri dal primo intervallo nel secondo intervallo.
Sarebbe bello avere questa funzionalità nella java.lang.Math
classe, poiché è una funzione così ampiamente richiesta ed è disponibile in altre lingue. Ecco una semplice implementazione:
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;
}
Metto questo codice qui come riferimento per il futuro me stesso e potrebbe essere che aiuterà qualcuno.
Per inciso, questo è lo stesso problema del classico converti celcius in farenheit in cui vuoi mappare un intervallo di numeri che equivale a 0-100 (C) a 32-212 (F).
Ogni intervallo unitario sul primo intervallo occupa (dc) / (ba) "spazio" sul secondo intervallo.
Pseudo:
var interval = (d-c)/(b-a)
for n = 0 to (b - a)
print c + n*interval
Come gestire l'arrotondamento dipende da te.
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);
Con controlli su dividi per zero, ovviamente.
se il tuo intervallo da [a a b] e vuoi mapparlo in [c a d] dove x è il valore che vuoi mappare usa questa formula (mappatura lineare)
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)