2008-12-05 16 views
65

Wie kann ich Zahlen linear zwischen a und b abbilden, um zwischen c und d zu wechseln?Math - Mapping-Nummern

Das heißt, ich möchte Zahlen zwischen 2 und 6 auf Zahlen zwischen 10 und 20 zuordnen ... aber ich brauche den verallgemeinerten Fall.

Mein Gehirn ist gebraten.

+3

Zweipunktform. http://en.wikipedia.org/wiki/Linear_equation#Two-point_form – kennytm

Antwort

16

Teilen Sie, um das Verhältnis zwischen den Größen der beiden Bereiche zu erhalten, subtrahieren Sie dann den Anfangswert Ihres Anfangsbereichs, multiplizieren Sie mit dem Verhältnis und addieren Sie den Anfangswert Ihres zweiten Bereichs. Mit anderen Worten,

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

Dies verteilt die Zahlen aus dem ersten Bereich im zweiten Bereich gleichmäßig.

+0

Dies funktioniert nicht. Mein Bereich ist 1000000000 bis 9999999999 und die Nummern könnten von 1 bis 999999999 sein. – Dejell

+0

@Odelya Natürlich funktioniert es. Es ist eine einfache mathematische Transformation. Sie müssen nur einen ausreichend großen Zahlentyp (bignum o.ä.) verwenden. Ihre Zahlen sind einfach zu groß für 32-Bit-Ganzzahlen - aber 64-Bit-Ganzzahlen zum Beispiel funktionieren. –

+0

Sie sind vom Typ doppelt. Doppel-R = (20 - 10)/(6 - 2); \t \t doppelt y = (X - 2) * R + 10; – Dejell

137

Wenn Ihre Zahl X zwischen A und B fällt, und Sie möchten, dass Y zwischen C und D fallen, können Sie die folgende lineare Transformation anwenden:

Y = (XA)/(BA) * (DC) + C

Das sollte Ihnen geben, was Sie wollen, obwohl Ihre Frage ein wenig mehrdeutig ist, da Sie auch das Intervall in umgekehrter Richtung zuordnen könnten. Achten Sie nur auf Division durch Null und Sie sollten in Ordnung sein.

+0

Danke. Genau das, was ich gesucht habe. – Sam

+31

Dann markieren Sie diese Antwort vielleicht als "akzeptiert", indem Sie auf das Häkchen daneben klicken. –

+0

Danke Peter, du bist fantastisch! – Adi

1

Jedes Einheitsintervall im ersten Bereich belegt (d-c)/(b-a) "Raum" im zweiten Bereich.

Pseudo:

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

Wie Sie die Rundung behandeln bis zu Ihnen ist.

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

Mit Checks auf teilen durch Null, natürlich.

2

Als beiseite, das ist das gleiche Problem wie die klassische convert Celcius farenheit, wo Sie einen Nummernbereich zugeordnet werden sollen, die 0 entspricht - 100 (C) 32 bis 212 (F).

+0

Wie ist das eine Antwort? – shinzou

+0

Es ist ein Beispiel für die Anwendung der Frage. Viele haben dieses einfache Problem in einführenden CS-Klassen und denken nicht, dass die Lösung für andere Probleme verallgemeinert werden kann. Ich habe versucht, der ursprünglichen Frage einen Kontext hinzuzufügen. Die ursprüngliche Frage wurde bereits ausreichend beantwortet. – Metro

0

Neben @PeterAllenWebb Antwort, wenn Sie das Ergebnis umkehren zurück möchten verwenden Sie die folgenden Schritte aus:

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

Es wäre schön, diese Funktionalität in der java.lang.Math Klasse zu haben, da dies so ist ein weit erforderliche Funktion und ist in anderen Sprachen verfügbar. Hier ist eine einfache Implementierung:

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

Ich stelle diesen Code hier als Referenz für die Zukunft selbst und kann es jemand helfen.