ฉันจะจับคู่ตัวเลขเชิงเส้นระหว่าง 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
ที่ม. และขได้รับการพิจารณาพร้อมกันจากสองต่อไปนี้สมการ จำกัด ที่เป็นผลมาจากการแทนค่าของ X และ Y ที่ปลายทางที่ต้องการ: C=m*A+b
และD=m*B+b
X=A+(A-B)*t
เพื่อพิสูจน์ความเท่าเทียมกันระหว่างแนวทางนี้กับของปีเตอร์ t คือการไม่มีมิติของ X ( t=(X-A)/(A-B)
)
หารเพื่อให้ได้อัตราส่วนระหว่างขนาดของช่วงสองช่วงจากนั้นลบค่าเริ่มต้นของช่วงอินิทัลของคุณคูณด้วยอัตราส่วนและเพิ่มค่าเริ่มต้นของช่วงที่สองของคุณ กล่าวอีกนัยหนึ่ง
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;
}
ฉันวางรหัสนี้ไว้ที่นี่เพื่อเป็นข้อมูลอ้างอิงสำหรับตัวฉันเองในอนาคตและอาจช่วยใครบางคน
นอกจากนี้ยังเป็นปัญหาเดียวกันกับการแปลง celcius แบบคลาสสิกเป็น farenheit ที่คุณต้องการแมปช่วงตัวเลขที่เท่ากับ 0-100 (C) ถึง 32-212 (F)
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)
แต่ละช่วงของหน่วยในช่วงแรกจะใช้พื้นที่ (dc) / (ba) "ช่องว่าง" ในช่วงที่สอง
หลอก:
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);
แน่นอนว่าด้วยการตรวจสอบการหารด้วยศูนย์
นอกจากคำตอบ @PeterAllenWebb แล้วหากคุณต้องการย้อนกลับผลลัพธ์ให้ใช้สิ่งต่อไปนี้:
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 )) จากนั้นแทนที่m ให้ใส่ ( X -A ) / ( B- A ) เพื่อรับY = C + ((( X )) สิ่งนี้ทำให้เรามีส่วนอื่นที่เราสามารถทำให้ง่ายขึ้น ( X - X *- ก ) / ( B - A )) * ( D - C )) นี่เป็นฟังก์ชั่นแผนที่ที่ใช้ได้ แต่สามารถทำให้ง่ายขึ้นได้ นำชิ้นส่วน( D - C ) มาใส่ในเงินปันผลเพื่อให้ได้Y = C + ((( X - A ) * ( D - C )) / ( B - A - C ) ซึ่งเท่ากับ ( A ) * ( DD ) - ( X * C ) - ( A * D ) + ( A * C ) ใส่เข้าไปแล้วคุณจะได้Y = C + ((( X * D ) - ( X * C ) - ( A * D ) + ( A * C )) / ( B - A )) สิ่งต่อไปที่คุณต้องทำคือเพิ่มบิต+ C ในการทำเช่นนั้นให้คุณคูณCด้วย ( ) เพื่อให้ได้ (( B * C ) - ( A * C B - A)) และย้ายเข้าไปในเงินปันผลเพื่อรับY = ((( X * D ) - ( X * C ) - ( A * D ) + ( A * C ) + ( B * C C ) และ a - ( A * C) - ( A * C )) / ( B - A )) สิ่งนี้ซ้ำซ้อนมีทั้ง a + ( A * Y = (( X * D ) - ( X * C ) - ( A * D ) + ( B )) / ( B * C ) ซึ่งจะยกเลิกซึ่งกันและกัน ลบออกและคุณจะได้รับผลลัพธ์สุดท้ายของ: - A )
TL; DR: ฟังก์ชั่นแผนที่มาตรฐานY = C + ((( X - A ) / ( B - A )) * ( D - C )) สามารถทำให้ง่ายลงเป็นY = (( X * D ) - ( X * C ) - ( A * D ) + ( B * C )) / ( B - A )