คณิตศาสตร์ - การจับคู่ตัวเลข


99

ฉันจะจับคู่ตัวเลขเชิงเส้นระหว่าง a และ b เพื่อไประหว่าง c และ d ได้อย่างไร

นั่นคือฉันต้องการให้ตัวเลขระหว่าง 2 ถึง 6 แมปกับตัวเลขระหว่าง 10 ถึง 20 ... แต่ฉันต้องการกรณีทั่วไป

สมองของฉันถูกทอด


4
แบบฟอร์มสองจุด en.wikipedia.org/wiki/Linear_equation#Two-point_form
kennytm

คำตอบ:


213

หากเลข X ของคุณอยู่ระหว่าง A และ B และคุณต้องการให้ Y อยู่ระหว่าง C และ D คุณสามารถใช้การแปลงเชิงเส้นต่อไปนี้:

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

นั่นควรให้สิ่งที่คุณต้องการแม้ว่าคำถามของคุณจะคลุมเครือเล็กน้อยเนื่องจากคุณสามารถจับคู่ช่วงเวลาในทิศทางย้อนกลับได้ เพียงระวังการหารด้วยศูนย์และคุณควรจะโอเค


17
เพื่อความชัดเจนฉันชอบ new_value = (old_value - old_bottom) / (old_top - old_bottom) * (new_top - new_bottom) + new_bottom;
ftrotter

1
สมการนี้มีที่มาหรือไม่?
shaveenk

@shaveenk มันควรจะเป็นสมการของเส้นกับY=f(X)=m*X+bที่ม. และขได้รับการพิจารณาพร้อมกันจากสองต่อไปนี้สมการ จำกัด ที่เป็นผลมาจากการแทนค่าของ X และ Y ที่ปลายทางที่ต้องการ: C=m*A+bและD=m*B+b
คริส Chiasson

ฉันยังต้องใช้X=A+(A-B)*tเพื่อพิสูจน์ความเท่าเทียมกันระหว่างแนวทางนี้กับของปีเตอร์ t คือการไม่มีมิติของ X ( t=(X-A)/(A-B))
Chris Chiasson

หากต้องการกลับทิศทางสูตรคือ ((XA) / (AB) * (CD)) * -1 + D
Corey Levinson

21

หารเพื่อให้ได้อัตราส่วนระหว่างขนาดของช่วงสองช่วงจากนั้นลบค่าเริ่มต้นของช่วงอินิทัลของคุณคูณด้วยอัตราส่วนและเพิ่มค่าเริ่มต้นของช่วงที่สองของคุณ กล่าวอีกนัยหนึ่ง

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

สิ่งนี้จะกระจายตัวเลขจากช่วงแรกในช่วงที่สองอย่างเท่าเทียมกัน


วิธีนี้ใช้ไม่ได้ ช่วงของฉันคือ 1000000000 ถึง 9999999999 และตัวเลขอาจเป็น 1 ถึง 999999999
Dejell

@Odelya ได้ผลแน่นอน มันเป็นการแปลงทางคณิตศาสตร์ที่ง่ายพอ คุณต้องใช้ประเภทตัวเลขที่มากพอ (เครื่องหมายใหญ่หรือคล้ายกัน) ตัวเลขของคุณใหญ่เกินไปสำหรับจำนวนเต็ม 32 บิต - แต่จำนวนเต็ม 64 บิตก็ใช้ได้เช่นกัน
Konrad Rudolph

เป็นประเภทคู่ คู่ R = (20 - 10) / (6 - 2); คู่ y = (X - 2) * R + 10;
Dejell

@Odelya ปัญหาเดียวกันว่า. คุณควรอ่านข้อมูลเกี่ยวกับความแม่นยำของจุดลอยตัว ในความเป็นจริงนี้จะต้องอ่าน: อะไรทุกนักวิทยาศาสตร์คอมพิวเตอร์ควรรู้เกี่ยวกับจุดลอยเลขคณิต - ถ้าคุณจำเป็นต้องมีชนิดลอยจุดที่มีตัวเลขใหญ่เช่นคุณอาจจะต้องใช้ความแม่นยำ arbitrary ประเภทหมายเลข
Konrad Rudolph

คุณสามารถแนะนำประเภท java ที่ฉันสามารถทำได้หรือไม่?
Dejell

7

จะเป็นการดีที่จะมีฟังก์ชันนี้ใน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;
}

ฉันวางรหัสนี้ไว้ที่นี่เพื่อเป็นข้อมูลอ้างอิงสำหรับตัวฉันเองในอนาคตและอาจช่วยใครบางคน


4

นอกจากนี้ยังเป็นปัญหาเดียวกันกับการแปลง celcius แบบคลาสสิกเป็น farenheit ที่คุณต้องการแมปช่วงตัวเลขที่เท่ากับ 0-100 (C) ถึง 32-212 (F)


นี่คือคำตอบอย่างไร?
shinzou

เป็นตัวอย่างของการประยุกต์ใช้คำถาม หลายคนมีปัญหาง่ายๆนี้ในชั้นเรียน CS เบื้องต้นและไม่คิดว่าวิธีแก้ปัญหานั้นสามารถนำไปสู่ปัญหาอื่น ๆ ฉันพยายามเพิ่มบริบทให้กับคำถามเดิม คำถามเดิมได้รับคำตอบอย่างเพียงพอแล้ว
เมโทร


1

แต่ละช่วงของหน่วยในช่วงแรกจะใช้พื้นที่ (dc) / (ba) "ช่องว่าง" ในช่วงที่สอง

หลอก:

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

วิธีจัดการกับการปัดเศษขึ้นอยู่กับคุณ


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

แน่นอนว่าด้วยการตรวจสอบการหารด้วยศูนย์


1

นอกจากคำตอบ @PeterAllenWebb แล้วหากคุณต้องการย้อนกลับผลลัพธ์ให้ใช้สิ่งต่อไปนี้:

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

1

ถ้าช่วงของคุณจาก [a ถึง b] และคุณต้องการแมปใน [c ถึง d] โดยที่ x คือค่าที่คุณต้องการแมปให้ใช้สูตรนี้ (การทำแผนที่เชิงเส้น)

double R = (d-c)/(b-a)
double y = c+(x*R)+R
return(y)

0

โดยที่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 )

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.