كيفية حساب قمة مكافحة البربون المعطى ثلاث نقاط

StackOverflow https://stackoverflow.com/questions/717762

  •  23-08-2019
  •  | 
  •  

سؤال

لدي ثلاث نقاط X / Y التي تشكل البطيء. أنا ببساطة بحاجة لحساب ما هو قمة الأخلاق التي تمر به هذه النقاط الثلاث. يفضل طريقة سريعة حيث يجب أن أفعل الكثير من هذه الحسابات!

يوفر موقع موقع "اسأل عاليم" هذه الإجابة:

يعطى المعادلة النموذج العام ل Parabola من قبل المعادلة: A * X ^ 2 + B * X + C = Y حيث A، B، و C، ثوابت حقيقية تعسفية. لديك ثلاثة أزواج من النقاط التي هي (x، y) مرتبة أزواج. استبدل قيم x و y من كل نقطة في المعادلة عن parabola. سوف تحصل على ثلاثة معادلات خطية في ثلاثة مجهولين، الثوابت الثلاثة. يمكنك بعد ذلك حل هذا النظام بسهولة من ثلاثة معادلات لقيم A، B، و C، وستحصل على معادلة Parabola التي تتقاطع 3 نقاط. The Vertex هو المكان الذي يوجد فيه أول مشتق 0، وهو القليل من الجبر يعطي: (-B / 2A، C - B ^ 2 / 4A) بالنسبة إلى Vertex.

سيكون من الجيد رؤية الرمز الفعلي الذي يقوم بهذا الحساب في C # أو C ++. اي شخص؟

هل كانت مفيدة؟

المحلول

هذا مجرد مشكلة جبرية خطية بسيطة، حتى تتمكن من القيام بالحساب رمزيا. عندما تكون بديلا في قيم X و Y في نقاطك الثلاث، ستحصل على ثلاث معادلات خطية في ثلاثة مجهولين.

A x1^2 + B x1 + C = y1
A x2^2 + B x2 + C = y2
A x3^2 + B x3 + C = y3

الطريقة المباشرة لحل هذا هو قلب المصفوفة

x1^2  x1  1
x2^2  x2  1
x3^2  x3  1

وضربها من قبل المتجه

y1
y2
y3

نتيجة هذا ... حسنا، ليس بالضبط كل هذا بسيط ؛-) لقد فعلت ذلك في الرياضيات، وهنا هي الصيغ في pseudocode:

denom = (x1 - x2)(x1 - x3)(x2 - x3)
A = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom
B = (x3^2 * (y1 - y2) + x2^2 * (y3 - y1) + x1^2 * (y2 - y3)) / denom
C = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom

بدلا من ذلك، إذا كنت ترغب في القيام بمصفوفة الرياضيات عدديا رقميا، فستتحول عادة إلى نظام جبري خطي (مثل أطلس, على الرغم من أنني لست متأكدا مما إذا كان لديه ارتباطات C # / C ++).

نصائح أخرى

شكرا ديفيد، قمت بتحويل الكود الكفولي الخاص بك إلى رمز C # التالية:

public static void CalcParabolaVertex(int x1, int y1, int x2, int y2, int x3, int y3, out double xv, out double yv)
{
    double denom = (x1 - x2) * (x1 - x3) * (x2 - x3);
    double A     = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom;
    double B     = (x3*x3 * (y1 - y2) + x2*x2 * (y3 - y1) + x1*x1 * (y2 - y3)) / denom;
    double C     = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom;

    xv = -B / (2*A);
    yv = C - B*B / (4*A);
}

هذا هو ما أردت. حساب بسيط لسأم بارابولا. سأتعامل مع زيادة عدد صحيح في وقت لاحق.

تحصل على المعادلات الثلاث التالية عن طريق الاستبدال المباشر:

A*x1^2+B*x1+C=y1
A*x2^2+B*x2+C=y2
A*x3^2+B*x3+C=y3

يمكنك حل هذا من خلال الإشارة إلى أن هذا يعادل منتج المصفوفة:

[x1^2 x1 1] [A]   [y1]
|x2^2 x2 1|*|B| = |y2|
[x3^2 x3 1] [C]   [y3]

بحيث يمكنك الحصول على، B، و C عن طريق تثبيت المصفوفة وضرب العكس مع ناقل

أرى أنه بينما كنت قد نشرت جون راشا قد ارتبط ببرنامج تعليمي يدخل في عمق أكبر في حل معادلة المصفوفة بالفعل، حتى تتمكن من اتباع هذه التعليمات للحصول على الإجابة. إن Enverting Matrix 3x3 سهل للغاية، لذلك لا ينبغي أن يكون هذا صعبا للغاية.

فيما يلي رمز في FORTRAN الذي ينفذ @ David-Z و @ حل Azdean:

subroutine parabola_vertex(x1, y1, x2, y2, x3, y3, xv, yv)
real(dp), intent(in) :: x1, y1, x2, y2, x3, y3
real(dp), intent(out) :: xv, yv
real(dp) :: denom, A, B, C
denom = (x1 - x2) * (x1 - x3) * (x2 - x3)
A     = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom
B     = (x3**2 * (y1 - y2) + x2**2 * (y3 - y1) + x1**2 * (y2 - y3)) / denom
C     = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + &
            x1 * x2 * (x1 - x2) * y3) / denom
xv = -B / (2*A)
yv = C - B**2 / (4*A)
end subroutine

لقد فعلت شيئا مشابها ل @ إجابة بيشوك، بناء على رمز @ Azdean. إذا كنت بحاجة إلى تشغيله بشدة (أو لاستخدامه في Matlab مثلي)، فقد يكون هذا أسرع واحد.

افتراضي هو ذلك x1 == -1, x2 == 0, x3 == 1.

a = y2 - ( y1 + y3) / 2   % opposite signal compared to the original definition of A
b = (y3 - y1) / 4         % half of the originally defined B

xExtr = b / a
yExtr = y2 + b * yExtr    % which is equal to y2 + b*b / a

هذه الرائحة مثل الواجبات المنزلية. "اسأل عالما" على حق. قل 3 نقاط الخاص بك هي (x1، y1)، (x2، y2)، و (x3، y3). بعد ذلك، تحصل على ثلاثة معادلات خطية:

| م11 م12 م13 | | A | | z.1 | | م21 م22 م23 | * |. ب | = | z.2 | | م31 م32 م33 | | ج | | z.3 |

حيث m.11 = X.12, ، م12 = X.1, ، م13 = 1، ض1 = Y.1, وبالمثل بالنسبة للصفتين الآخرين باستخدام (X2 و Y2) و (X3 و Y3) بدلا من (X1 و Y1).

حل هذا النظام من 3 معادلات سوف تعطيك حلا ل A، B، و C.

def vertex(x1,x2,x3,y1,y2,y3):
    '''Given three pairs of (x,y) points return the vertex of the
         parabola passing through the points. Vectorized and common expression reduced.'''
    #Define a sequence of sub expressions to reduce redundant flops
    x0 = 1/x2
    x4 = x1 - x2
    x5 = 1/x4
    x6 = x1**2
    x7 = 1/x6
    x8 = x2**2
    x9 = -x7*x8 + 1
    x10 = x0*x1*x5*x9
    x11 = 1/x1
    x12 = x3**2
    x13 = x11*x12
    x14 = 1/(x0*x13 - x0*x3 - x11*x3 + 1)
    x15 = x14*y3
    x16 = x10*x15
    x17 = x0*x5
    x18 = -x13 + x3
    x19 = y2*(x1*x17 + x14*x18*x6*x9/(x4**2*x8))
    x20 = x2*x5
    x21 = x11*x20
    x22 = x14*(-x12*x7 + x18*x21)
    x23 = y1*(-x10*x22 - x21)
    x24 = x16/2 - x19/2 - x23/2
    x25 = -x17*x9 + x7
    x26 = x0*x1*x14*x18*x5
    x27 = 1/(-x15*x25 + y1*(x20*x7 - x22*x25 + x7) + y2*(-x17 + x25*x26))
    x28 = x24*x27
    return x28,x15 + x22*y1 + x24**2*x27 - x26*y2 + x28*(-x16 + x19 + x23)

تشغيل في https://ideone.com/y0sxku.

#include <iostream>
using namespace std;
// calculate the vertex of a parabola given three points
// https://stackoverflow.com/q/717762/16582

// @AZDean implementation with given x values

void CalcParabolaVertex(int x1, int y1, int x2, int y2, int x3, int y3, double& xv,  double& yv)
{
    double denom = (x1 - x2) * (x1 - x3) * (x2 - x3);
    double A     = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / denom;
    double B     = (x3*x3 * (y1 - y2) + x2*x2 * (y3 - y1) + x1*x1 * (y2 - y3)) / denom;
    double C     = (x2 * x3 * (x2 - x3) * y1 + x3 * x1 * (x3 - x1) * y2 + x1 * x2 * (x1 - x2) * y3) / denom;

    xv = -B / (2*A);
    yv = C - B*B / (4*A);
}

// @piSHOCK immplementation assuming regular x values ( wrong!!! )

void CalcParabolaVertex2( int y1, int y2, int y3, double& xv,  double& yv)
{
double d1 = y1 - y2;
double d2 = y1 - y3;

double a =    -d1 + 0.5 * d2;
double b = 2 * d1 - 0.5 * d2;
double c = -y1;

xv =    -0.5      * b / a;
yv = c - 0.25 * b * b / a;  
}

// corrected immplementation assuming regular x values

void CalcParabolaVertex3( int y1, int y2, int y3, double& xv,  double& yv)
{
double d1 = y1 - y2;
double d2 = y1 - y3;

double a = d1 - 0.5 * d2;
double b = -2 * d1 + 0.5 * d2;
double c = y1;

xv =    -0.5      * b / a;
yv = c - 0.25 * b * b / a;  
}


int main() {
    double xv, yv;
    CalcParabolaVertex( 0, 100, 1, 500, 2, 200, xv, yv );
    cout << xv <<" "<< yv << "\n";
    CalcParabolaVertex2( 100, 500, 200, xv, yv );
    cout << xv <<" "<< yv << "\n";
    CalcParabolaVertex3( 100, 500, 200, xv, yv );
    cout << xv <<" "<< yv << "\n";
    return 0;
}

لقد أضفت اختبارات بضع وحدة للحصول على قمم السلبية: تشغيل مباشر في https://ideone.com/wgk90s.

إذا قمت بتقديم افتراض ذلك x1 == 0, x2 == 1, x3 == 2, على سبيل المثال عند تركيب منحنى محلي إلى بعض إشارة أخذ العينات بشكل موحد، يفسد كود Isdean إلى:

d1 = y1 - y2
d2 = y1 - y3

a =      d1 - 0.5 * d2
b = -2 * d1 + 0.5 * d2
c = y1

xVertex =    -0.5      * b / a
yVertex = c - 0.25 * b * b / a
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top