سؤال

أريد أن برمجيا حل نظام من المعادلات الخطية في ج ، ج موضوعية ، أو (إذا لزم الأمر) C++.

هنا مثال على المعادلات:

-44.3940 = a * 50.0 + b * 37.0 + tx
-45.3049 = a * 43.0 + b * 39.0 + tx
-44.9594 = a * 52.0 + b * 41.0 + tx

من هذا, أود أن أحصل على أفضل التقديرات التقريبية a, b, ، tx.

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

المحلول

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

تحرير:أعلم أنك تعمل في ج الأراضي ، ولكن أنا أيضا يجب أن نضع في كلمة طيبة SymPy (كمبيوتر نظام الجبر في بيثون).يمكنك أن تتعلم الكثير من الخوارزميات (إذا كان يمكنك أن تقرأ قليلا من بيثون).كما انها تحت رخصة BSD, في حين أن معظم الرياضيات الحرة حزم GPL.

نصائح أخرى

يمكنك حل هذا مع البرنامج بالضبط نفس طريقة حل باليد (مع الضرب والطرح ، ثم تغذية النتائج مرة أخرى في المعادلات).هذا هو معيار جميلة المدارس الثانوية على مستوى الرياضيات.

-44.3940 = 50a + 37b + c (A)
-45.3049 = 43a + 39b + c (B)
-44.9594 = 52a + 41b + c (C)

(A-B): 0.9109 =  7a -  2b (D)
(B-C): 0.3455 = -9a -  2b (E)

(D-E): 1.2564 = 16a (F)

(F/16):  a = 0.078525 (G)

Feed G into D:
       0.9109 = 7a - 2b
    => 0.9109 = 0.549675 - 2b (substitute a)
    => 0.361225 = -2b (subtract 0.549675 from both sides)
    => -0.1806125 = b (divide both sides by -2) (H)

Feed H/G into A:
       -44.3940 = 50a + 37b + c
    => -44.3940 = 3.92625 - 6.6826625 + c (substitute a/b)
    => -41.6375875 = c (subtract 3.92625 - 6.6826625 from both sides)

إذا كنت في نهاية المطاف مع:

a =   0.0785250
b =  -0.1806125
c = -41.6375875

إذا قمت بتوصيل هذه القيم مرة أخرى إلى A, B, C, ستجد أنها صحيحة.

الحيلة هي أن استخدام بسيط 4x3 مصفوفة مما يقلل بدوره إلى 3x2 مصفوفة ، ثم 2x1 الذي هو "أ = ن" ، ن كونه العدد الفعلي.وبمجرد الانتهاء من ذلك يمكنك إطعام في القادم مصفوفة للحصول على قيمة أخرى ، ثم هذين القيم التالية مصفوفة حتى تحل جميع المتغيرات.

شريطة أن يكون لديك N متميزة المعادلات, يمكنك دائما حل ن المتغيرات.أقول متميزة لأن هذين لا:

 7a + 2b =  50
14a + 4b = 100

هم نفس المعادلة مضروبا في اثنين حتى تتمكن من الحصول على حل منها - ضرب أول اثنين ثم طرح يترك لك مع صحيح ولكن بلا جدوى البيان:

0 = 0 + 0

على سبيل المثال, هنا بعض التعليمات البرمجية C الذي يعمل خارج المعادلات الآنية التي كنت وضعت في سؤالك.أولا بعض أنواع المتغيرات دعم وظيفة الطباعة خارج المعادلة ، بداية من main:

#include <stdio.h>

typedef struct { double r, a, b, c; } tEquation;
tEquation equ1[] = {
    { -44.3940,  50, 37, 1 },      // -44.3940 = 50a + 37b + c (A)
    { -45.3049,  43, 39, 1 },      // -45.3049 = 43a + 39b + c (B)
    { -44.9594,  52, 41, 1 },      // -44.9594 = 52a + 41b + c (C)
};
tEquation equ2[2], equ3[1];

static void dumpEqu (char *desc, tEquation *e, char *post) {
    printf ("%10s: %12.8lf = %12.8lfa + %12.8lfb + %12.8lfc (%s)\n",
        desc, e->r, e->a, e->b, e->c, post);
}

int main (void) {
    double a, b, c;

المقبل, الحد من ثلاث معادلات بثلاث مجاهيل إلى معادلتين مع اثنين من المجاهيل:

    // First step, populate equ2 based on removing c from equ.

    dumpEqu (">", &(equ1[0]), "A");
    dumpEqu (">", &(equ1[1]), "B");
    dumpEqu (">", &(equ1[2]), "C");
    puts ("");

    // A - B
    equ2[0].r = equ1[0].r * equ1[1].c - equ1[1].r * equ1[0].c;
    equ2[0].a = equ1[0].a * equ1[1].c - equ1[1].a * equ1[0].c;
    equ2[0].b = equ1[0].b * equ1[1].c - equ1[1].b * equ1[0].c;
    equ2[0].c = 0;

    // B - C
    equ2[1].r = equ1[1].r * equ1[2].c - equ1[2].r * equ1[1].c;
    equ2[1].a = equ1[1].a * equ1[2].c - equ1[2].a * equ1[1].c;
    equ2[1].b = equ1[1].b * equ1[2].c - equ1[2].b * equ1[1].c;
    equ2[1].c = 0;

    dumpEqu ("A-B", &(equ2[0]), "D");
    dumpEqu ("B-C", &(equ2[1]), "E");
    puts ("");

المقبل, الحد من معادلتين مع اثنين من المجاهيل إلى معادلة واحدة مع واحد غير معروف:

    // Next step, populate equ3 based on removing b from equ2.

    // D - E
    equ3[0].r = equ2[0].r * equ2[1].b - equ2[1].r * equ2[0].b;
    equ3[0].a = equ2[0].a * equ2[1].b - equ2[1].a * equ2[0].b;
    equ3[0].b = 0;
    equ3[0].c = 0;

    dumpEqu ("D-E", &(equ3[0]), "F");
    puts ("");

الآن أن لدينا صيغة من نوع number1 = unknown * number2, يمكننا ببساطة العمل مجهولة القيمة مع unknown <- number1 / number2.ثم, مرة واحدة كنت قد اكتشفت أن قيمة, بديلا في واحدة من المعادلات مع اثنين من المجاهيل والعمل على القيمة الثانية.ثم استبدال كل تلك (الآن معروفة) المجاهيل في واحدة من الأصلي المعادلات والآن لديك قيم كل ثلاثة مجاهيل:

    // Finally, substitute values back into equations.

    a = equ3[0].r / equ3[0].a;
    printf ("From (F    ), a = %12.8lf (G)\n", a);

    b = (equ2[0].r - equ2[0].a * a) / equ2[0].b;
    printf ("From (D,G  ), b = %12.8lf (H)\n", b);

    c = (equ1[0].r - equ1[0].a * a - equ1[0].b * b) / equ1[0].c;
    printf ("From (A,G,H), c = %12.8lf (I)\n", c);

    return 0;
}

الإخراج من أن رمز مباريات في وقت سابق من العمليات الحسابية في هذا الجواب:

         >: -44.39400000 =  50.00000000a +  37.00000000b +   1.00000000c (A)
         >: -45.30490000 =  43.00000000a +  39.00000000b +   1.00000000c (B)
         >: -44.95940000 =  52.00000000a +  41.00000000b +   1.00000000c (C)

       A-B:   0.91090000 =   7.00000000a +  -2.00000000b +   0.00000000c (D)
       B-C:  -0.34550000 =  -9.00000000a +  -2.00000000b +   0.00000000c (E)

       D-E:  -2.51280000 = -32.00000000a +   0.00000000b +   0.00000000c (F)

From (F    ), a =   0.07852500 (G)
From (D,G  ), b =  -0.18061250 (H)
From (A,G,H), c = -41.63758750 (I)

بالنسبة 3x3 نظام من المعادلات الخطية أعتقد أنه سيكون بخير لفة الخاص بك الخوارزميات.

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

نلقي نظرة على مايكروسوفت حلالا مؤسسة.

مع أنه يمكن أن تكتب رمز مثل هذا:

  SolverContext context = SolverContext.GetContext();
  Model model = context.CreateModel();

  Decision a = new Decision(Domain.Real, "a");
  Decision b = new Decision(Domain.Real, "b");
  Decision c = new Decision(Domain.Real, "c");
  model.AddDecisions(a,b,c);
  model.AddConstraint("eqA", -44.3940 == 50*a + 37*b + c);
  model.AddConstraint("eqB", -45.3049 == 43*a + 39*b + c);
  model.AddConstraint("eqC", -44.9594 == 52*a + 41*b + c);
  Solution solution = context.Solve();
  string results = solution.GetReport().ToString();
  Console.WriteLine(results); 

هنا هو الإخراج:
===حلالا مؤسسة الخدمة التقرير===
التاريخ والوقت:04/20/2009 23:29:55
اسم النموذج:الافتراضي
القدرات المطلوبة:LP
حل الوقت (ms):1027
إجمالي الوقت (ms):1414
حل الانتهاء الحالة:الأمثل
حلالا المختارة:مايكروسوفت.SolverFoundation.يحلون.SimplexSolver
التوجيهات:
مايكروسوفت.SolverFoundation.الخدمات.التوجيه
الخوارزمية:البدائية
الحساب:الهجين
التسعير (الدقيق):الافتراضي
التسعير (مزدوجة):SteepestEdge
أساس:الركود
محور العد:3
===الحل التفاصيل===
الأهداف:

القرارات:
a:0.0785250000000004
ب:-0.180612500000001
ج:-41.6375875

هل تبحث عن مجموعة من البرامج التي سوف تفعل العمل أو يفعل فعلا مصفوفة العمليات و هكذا تفعل في كل خطوة ؟

في أول زميل في العمل من الألغام تستخدم فقط Ocaml GLPK.هو مجرد التفاف على GLPK, ولكنه يزيل الكثير من الخطوات من وضع الأمور.يبدو عليك التمسك GLPK ، ج ، على الرغم من.لهذا الأخير ، بفضل لذيذ لإنقاذ قديمة المادة كنت تعلم LP لحظة العودة ، PDF.إذا كنت بحاجة إلى مساعدة محددة إنشاء المزيد, اسمحوا لنا أن نعرف و أنا متأكد أنا أو أي شخص سوف يهيمون على وجوههم مرة أخرى ، ولكن أعتقد أنه إلى حد ما على التوالي إلى الأمام من هنا.حظا سعيدا!

قالب العددية أدوات من NIST لديه أدوات للقيام بذلك.

واحدة من أكثر موثوقية الطرق هو استخدام تحليل QR.

هنا مثال من المجمع حتى أستطيع أن أسميه "GetInverse(أ ، InvA)" في قانون بلدي وسوف وضع معكوس في InvA.

void GetInverse(const Array2D<double>& A, Array2D<double>& invA)
   {
   QR<double> qr(A);  
   invA = qr.solve(I); 
   }

Array2D يتم تعريفه في المكتبة.

من صيغة السؤال, يبدو أن لديك أكثر المعادلات من المجاهيل و كنت ترغب في تقليل حالات عدم تناسق.ويتم هذا عادة مع الانحدار الخطي ، مما يقلل من مجموع المربعات من التناقضات.اعتمادا على حجم البيانات في جدول بيانات أو في الحزمة الإحصائية.R هي عالية الجودة حزمة مجانية لا الانحدار الخطي ، من بين الكثير من الأشياء الأخرى.هناك الكثير الانحدار الخطي (و الكثير من مسكتك) ، ولكن كما انها واضحة للقيام الحالات البسيطة.وهنا R على سبيل المثال استخدام البيانات الخاصة بك.علما أن "تكساس" هو اعتراض على النموذج الخاص بك.

> y <- c(-44.394, -45.3049, -44.9594)
> a <- c(50.0, 43.0, 52.0)
> b <- c(37.0, 39.0, 41.0)
> regression = lm(y ~ a + b)
> regression

Call:
lm(formula = y ~ a + b)

Coefficients:
(Intercept)            a            b  
  -41.63759      0.07852     -0.18061  

من حيث وقت التشغيل الكفاءة ، والبعض الآخر يكون الرد أفضل من الأول.إذا كنت دائما وسوف يكون نفس العدد من المعادلات كما متغيرات أحب قاعدة كرامر كما انها سهلة التنفيذ.مجرد كتابة دالة لحساب محدد مصفوفة (أو استخدام واحدة مكتوبة بالفعل, أنا متأكد من أنك يمكن أن تجد واحدة من هناك) و تقسيم المحددات اثنين من المصفوفات.

شخصيا, أنا جزء من خوارزميات العددية وصفات.(أنا مولعا C++ الإصدار.)

هذا الكتاب سوف يعلمك لماذا خوارزميات العمل ، بالإضافة إلى عرض بعض جدا-حسنا تصحيحه تطبيقات تلك الخوارزميات.

بالطبع, يمكنك فقط استخدام عمياء CLAPACK (كنت استخدمه مع النجاح الكبير) ، ولكن أود أن أول يد-اكتب القضاء جاوس خوارزمية أن يكون لديك على الأقل فكرة خافت من هذا النوع من العمل الذي بذل في صنع هذه الخوارزميات مستقرة.

في وقت لاحق, إذا كنت تريد أن تفعل أكثر إثارة للاهتمام الجبر الخطي ، وتبحث في جميع أنحاء البرمجية المصدر اوكتاف سيتم الإجابة على الكثير من الأسئلة.

function x = LinSolve(A,y)
%
% Recursive Solution of Linear System Ax=y
% matlab equivalent: x = A\y 
% x = n x 1
% A = n x n
% y = n x 1
% Uses stack space extensively. Not efficient.
% C allows recursion, so convert it into C. 
% ----------------------------------------------
n=length(y);
x=zeros(n,1);
if(n>1)
    x(1:n-1,1) = LinSolve( A(1:n-1,1:n-1) - (A(1:n-1,n)*A(n,1:n-1))./A(n,n) , ...
                           y(1:n-1,1) - A(1:n-1,n).*(y(n,1)/A(n,n))); 
    x(n,1) = (y(n,1) - A(n,1:n-1)*x(1:n-1,1))./A(n,n); 
else
    x = y(1,1) / A(1,1);
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top