我需要以编程方式求解C,Objective C或(如果需要)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

由此,我想获得abtx的最佳近似值。

===============>>#1 票数:19 已采纳

Cramer规则高斯消去法是两个很好的通用算法(另请参见线性方程组 )。 如果您正在寻找代码,请查看GiNaCMaximaSymbolicC ++ (当然,这取决于您的许可要求)。

编辑:我知道您在C领域中工作,但我也必须对SymPy (Python中的计算机代数系统)说一个好话。 您可以从其算法中学到很多东西(如果您可以阅读一些python)。 此外,它还获得了新的BSD许可,而大多数免费数学软件包都是GPL。

===============>>#2 票数:15

您可以使用与手动求解完全相同的方法来解决此问题(通过相乘和相减,然后将结果反馈到方程式中)。 这是相当标准的中学数学。

-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,即“ a = n”,n为实际数字。 一旦有了,就将其馈入下一个矩阵以获取另一个值,然后将这两个值馈入下一个矩阵,直到解决所有变量为止。

如果您有N个不同的方程式,则始终可以求解N个变量。 我说与众不同是因为这两个不是:

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

它们是相同的方程式乘以2,所以您无法从中获得解决方案-将第一个乘以2,然后减去,得到的是真实但无用的语句:

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)

===============>>#3 票数:7

对于线性方程组的3x3系统,我想可以推出自己的算法了。

但是,您可能需要担心准确性,被零除或很小的数字以及如何处理无限多个解决方案。 我的建议是使用标准数字线性代数软件包,例如LAPACK

===============>>#4 票数:6

看一下Microsoft Solver Foundation

有了它,您可以编写如下代码:

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

这是输出:
=== Solver Foundation服务报告===
日期时间:2009年4月20日23:29:55
型号名称:默认
要求的能力:LP
解决时间(毫秒):1027
总时间(毫秒):1414
解决完成状态:最佳
已选择求解器:Microsoft.SolverFoundation.Solvers.SimplexSolver
指令:
Microsoft.SolverFoundation.Services.Directive
算法:原始
算术:混合
定价(精确):默认
定价(双):SteepestEdge
依据:松弛
枢轴数:3
===解决方案详细信息===
目标:

决定:
一个:0.0785250000000004
b:-0.180612500000001
c:-41.6375875

===============>>#5 票数:3

NIST的模板数值工具包提供了用于执行此操作的工具。

一种更可靠的方法是使用QR分解

这是一个包装器的示例,因此我可以在代码中调用“ GetInverse(A,InvA)”,并将其放入InvA中。

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

Array2D在库中定义。

===============>>#6 票数:3

您是否正在寻找一个可以完成工作或实际执行矩阵运算等工作的软件包,并且每个步骤都在做?

第一个是我的同事,刚用过Ocaml GLPK 它只是GLPK的包装,但是它消除了许多设置步骤。 但是,看起来您将不得不使用C中的GLPK。 对于后者,多亏了Delicious节省了我以前用来学习LP的旧文章PDF 如果您需要进一步的具体帮助,请告诉我们,我敢肯定,我或某人会回过头来寻求帮助,但是,我认为从这里开始是很直接的。 祝好运!

===============>>#7 票数:2

从问题的措辞来看,似乎方程式多于未知数,并且您希望最大程度地减少不一致之处。 通常使用线性回归来完成,这可以最小化不一致的平方和。 根据数据的大小,您可以在电子表格或统计数据包中执行此操作。 R是高质量的免费软件包,可以进行线性回归,还有很多其他事情。 线性回归(以及很多陷阱)有很多,但是对于简单的案例来说很简单。 这是一个使用您的数据的R示例。 请注意,“ tx”是模型的截距。

> 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  

===============>>#8 票数:2

在运行时效率方面,其他人的回答比我要好。如果您总是拥有与变量相同的方程式,那么我喜欢Cramer规则,因为它易于实现。 只需编写一个函数来计算矩阵的行列式(或使用已经编写的函数,我确定您可以在其中找到一个),然后将两个矩阵的行列式相除。

===============>>#9 票数:1

就个人而言,我偏爱数字食谱的算法。 (我喜欢C ++版。)

本书将教您算法为何起作用,并向您展示这些算法的一些调试良好的实现。

当然,您可以盲目使用CLAPACK (我已经非常成功地使用了它),但是我首先要手动输入一个高斯消除算法,以至少对创建这些算法的工作类型有一个模糊的认识稳定。

以后,如果您要进行更有趣的线性代数运算,那么看看Octave的源代码将回答很多问题。

===============>>#10 票数:1

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

  ask by Adam Ernst translate from so

未解决问题?本站智能推荐:

关注微信公众号