Simple 3x3 matrix inverse code (C++)

后端 未结 13 2017
花落未央
花落未央 2020-12-04 19:35

What\'s the easiest way to compute a 3x3 matrix inverse?

I\'m just looking for a short code snippet that\'ll do the trick for non-singular matrices, possibly using C

相关标签:
13条回答
  • 2020-12-04 20:05

    With all due respect to our unknown (yahoo) poster, I look at code like that and just die a little inside. Alphabet soup is just so insanely difficult to debug. A single typo anywhere in there can really ruin your whole day. Sadly, this particular example lacked variables with underscores. It's so much more fun when we have a_b-c_d*e_f-g_h. Especially when using a font where _ and - have the same pixel length.

    Taking up Suvesh Pratapa on his suggestion, I note:

    Given 3x3 matrix:
           y0x0  y0x1  y0x2
           y1x0  y1x1  y1x2
           y2x0  y2x1  y2x2
    Declared as double matrix [/*Y=*/3] [/*X=*/3];
    

    (A) When taking a minor of a 3x3 array, we have 4 values of interest. The lower X/Y index is always 0 or 1. The higher X/Y index is always 1 or 2. Always! Therefore:

    double determinantOfMinor( int          theRowHeightY,
                               int          theColumnWidthX,
                               const double theMatrix [/*Y=*/3] [/*X=*/3] )
    {
      int x1 = theColumnWidthX == 0 ? 1 : 0;  /* always either 0 or 1 */
      int x2 = theColumnWidthX == 2 ? 1 : 2;  /* always either 1 or 2 */
      int y1 = theRowHeightY   == 0 ? 1 : 0;  /* always either 0 or 1 */
      int y2 = theRowHeightY   == 2 ? 1 : 2;  /* always either 1 or 2 */
    
      return ( theMatrix [y1] [x1]  *  theMatrix [y2] [x2] )
          -  ( theMatrix [y1] [x2]  *  theMatrix [y2] [x1] );
    }
    

    (B) Determinant is now: (Note the minus sign!)

    double determinant( const double theMatrix [/*Y=*/3] [/*X=*/3] )
    {
      return ( theMatrix [0] [0]  *  determinantOfMinor( 0, 0, theMatrix ) )
          -  ( theMatrix [0] [1]  *  determinantOfMinor( 0, 1, theMatrix ) )
          +  ( theMatrix [0] [2]  *  determinantOfMinor( 0, 2, theMatrix ) );
    }
    

    (C) And the inverse is now:

    bool inverse( const double theMatrix [/*Y=*/3] [/*X=*/3],
                        double theOutput [/*Y=*/3] [/*X=*/3] )
    {
      double det = determinant( theMatrix );
    
        /* Arbitrary for now.  This should be something nicer... */
      if ( ABS(det) < 1e-2 )
      {
        memset( theOutput, 0, sizeof theOutput );
        return false;
      }
    
      double oneOverDeterminant = 1.0 / det;
    
      for (   int y = 0;  y < 3;  y ++ )
        for ( int x = 0;  x < 3;  x ++   )
        {
            /* Rule is inverse = 1/det * minor of the TRANSPOSE matrix.  *
             * Note (y,x) becomes (x,y) INTENTIONALLY here!              */
          theOutput [y] [x]
            = determinantOfMinor( x, y, theMatrix ) * oneOverDeterminant;
    
            /* (y0,x1)  (y1,x0)  (y1,x2)  and (y2,x1)  all need to be negated. */
          if( 1 == ((x + y) % 2) )
            theOutput [y] [x] = - theOutput [y] [x];
        }
    
      return true;
    }
    

    And round it out with a little lower-quality testing code:

    void printMatrix( const double theMatrix [/*Y=*/3] [/*X=*/3] )
    {
      for ( int y = 0;  y < 3;  y ++ )
      {
        cout << "[  ";
        for ( int x = 0;  x < 3;  x ++   )
          cout << theMatrix [y] [x] << "  ";
        cout << "]" << endl;
      }
      cout << endl;
    }
    
    void matrixMultiply(  const double theMatrixA [/*Y=*/3] [/*X=*/3],
                          const double theMatrixB [/*Y=*/3] [/*X=*/3],
                                double theOutput  [/*Y=*/3] [/*X=*/3]  )
    {
      for (   int y = 0;  y < 3;  y ++ )
        for ( int x = 0;  x < 3;  x ++   )
        {
          theOutput [y] [x] = 0;
          for ( int i = 0;  i < 3;  i ++ )
            theOutput [y] [x] +=  theMatrixA [y] [i] * theMatrixB [i] [x];
        }
    }
    
    int
    main(int argc, char **argv)
    {
      if ( argc > 1 )
        SRANDOM( atoi( argv[1] ) );
    
      double m[3][3] = { { RANDOM_D(0,1e3), RANDOM_D(0,1e3), RANDOM_D(0,1e3) },
                         { RANDOM_D(0,1e3), RANDOM_D(0,1e3), RANDOM_D(0,1e3) },
                         { RANDOM_D(0,1e3), RANDOM_D(0,1e3), RANDOM_D(0,1e3) } };
      double o[3][3], mm[3][3];
    
      if ( argc <= 2 )
        cout << fixed << setprecision(3);
    
      printMatrix(m);
      cout << endl << endl;
    
      SHOW( determinant(m) );
      cout << endl << endl;
    
      BOUT( inverse(m, o) );
      printMatrix(m);
      printMatrix(o);
      cout << endl << endl;
    
      matrixMultiply (m, o, mm );
      printMatrix(m);
      printMatrix(o);
      printMatrix(mm);  
      cout << endl << endl;
    }
    

    Afterthought:

    You may also want to detect very large determinants as round-off errors will affect your accuracy!

    0 讨论(0)
  • 2020-12-04 20:07

    Here's a version of batty's answer, but this computes the correct inverse. batty's version computes the transpose of the inverse.

    // computes the inverse of a matrix m
    double det = m(0, 0) * (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2)) -
                 m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
                 m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0));
    
    double invdet = 1 / det;
    
    Matrix33d minv; // inverse of matrix m
    minv(0, 0) = (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2)) * invdet;
    minv(0, 1) = (m(0, 2) * m(2, 1) - m(0, 1) * m(2, 2)) * invdet;
    minv(0, 2) = (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * invdet;
    minv(1, 0) = (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) * invdet;
    minv(1, 1) = (m(0, 0) * m(2, 2) - m(0, 2) * m(2, 0)) * invdet;
    minv(1, 2) = (m(1, 0) * m(0, 2) - m(0, 0) * m(1, 2)) * invdet;
    minv(2, 0) = (m(1, 0) * m(2, 1) - m(2, 0) * m(1, 1)) * invdet;
    minv(2, 1) = (m(2, 0) * m(0, 1) - m(0, 0) * m(2, 1)) * invdet;
    minv(2, 2) = (m(0, 0) * m(1, 1) - m(1, 0) * m(0, 1)) * invdet;
    
    0 讨论(0)
  • 2020-12-04 20:13

    Why don't you try to code it yourself? Take it as a challenge. :)

    For a 3×3 matrix


    (source: wolfram.com)

    the matrix inverse is


    (source: wolfram.com)

    I'm assuming you know what the determinant of a matrix |A| is.

    Images (c) Wolfram|Alpha and mathworld.wolfram (06-11-09, 22.06)

    0 讨论(0)
  • 2020-12-04 20:15

    This piece of code computes the transposed inverse of the matrix A:

    double determinant =    +A(0,0)*(A(1,1)*A(2,2)-A(2,1)*A(1,2))
                            -A(0,1)*(A(1,0)*A(2,2)-A(1,2)*A(2,0))
                            +A(0,2)*(A(1,0)*A(2,1)-A(1,1)*A(2,0));
    double invdet = 1/determinant;
    result(0,0) =  (A(1,1)*A(2,2)-A(2,1)*A(1,2))*invdet;
    result(1,0) = -(A(0,1)*A(2,2)-A(0,2)*A(2,1))*invdet;
    result(2,0) =  (A(0,1)*A(1,2)-A(0,2)*A(1,1))*invdet;
    result(0,1) = -(A(1,0)*A(2,2)-A(1,2)*A(2,0))*invdet;
    result(1,1) =  (A(0,0)*A(2,2)-A(0,2)*A(2,0))*invdet;
    result(2,1) = -(A(0,0)*A(1,2)-A(1,0)*A(0,2))*invdet;
    result(0,2) =  (A(1,0)*A(2,1)-A(2,0)*A(1,1))*invdet;
    result(1,2) = -(A(0,0)*A(2,1)-A(2,0)*A(0,1))*invdet;
    result(2,2) =  (A(0,0)*A(1,1)-A(1,0)*A(0,1))*invdet;
    

    Though the question stipulated non-singular matrices, you might still want to check if determinant equals zero (or very near zero) and flag it in some way to be safe.

    0 讨论(0)
  • 2020-12-04 20:17
    //Function for inverse of the input square matrix 'J' of dimension 'dim':
    
    vector<vector<double > > inverseVec33(vector<vector<double > > J, int dim)
    {
    //Matrix of Minors
     vector<vector<double > > invJ(dim,vector<double > (dim));
    for(int i=0; i<dim; i++)
    {
        for(int j=0; j<dim; j++)
        {
            invJ[i][j] = (J[(i+1)%dim][(j+1)%dim]*J[(i+2)%dim][(j+2)%dim] -
                          J[(i+2)%dim][(j+1)%dim]*J[(i+1)%dim][(j+2)%dim]);
        }
    }
    
    //determinant of the matrix:
    double detJ = 0.0;
    for(int j=0; j<dim; j++)
    { detJ += J[0][j]*invJ[0][j];}
    
    //Inverse of the given matrix.
     vector<vector<double > > invJT(dim,vector<double > (dim));
     for(int i=0; i<dim; i++)
    {
        for(int j=0; j<dim; j++)
        {
            invJT[i][j] = invJ[j][i]/detJ;
        }
    }
    
    return invJT;
    }
    
    void main()
    {
        //given matrix:
    vector<vector<double > > Jac(3,vector<double > (3));
    Jac[0][0] = 1; Jac[0][1] = 2;  Jac[0][2] = 6;
    Jac[1][0] = -3; Jac[1][1] = 4;  Jac[1][2] = 3;
    Jac[2][0] = 5; Jac[2][1] = 1;  Jac[2][2] = -4;`
    
    //Inverse of the matrix Jac:
    vector<vector<double > > JacI(3,vector<double > (3));
        //call function and store inverse of J as JacI:
    JacI = inverseVec33(Jac,3);
    }
    
    0 讨论(0)
  • 2020-12-04 20:21
    # include <conio.h>
    # include<iostream.h>
    
    const int size = 9;
    
    int main()
    {
        char ch;
    
        do
        {
            clrscr();
            int i, j, x, y, z, det, a[size], b[size];
    
            cout << "           **** MATRIX OF 3x3 ORDER ****"
                 << endl
                 << endl
                 << endl;
    
            for (i = 0; i <= size; i++)
                a[i]=0;
    
            for (i = 0; i < size; i++)
            {
                cout << "Enter "
                     << i + 1
                     << " element of matrix=";
    
                cin >> a[i]; 
    
                cout << endl
                     <<endl;
            }
    
            clrscr();
    
            cout << "your entered matrix is "
                 << endl
                 <<endl;
    
            for (i = 0; i < size; i += 3)
                cout << a[i]
                     << "  "
                     << a[i+1]
                     << "  "
                     << a[i+2]
                     << endl
                     <<endl;
    
            cout << "Transpose of given matrix is"
                 << endl
                 << endl;
    
            for (i = 0; i < 3; i++)
                cout << a[i]
                     << "  "
                     << a[i+3]
                     << "  "
                     << a[i+6]
                     << endl
                     << endl;
    
            cout << "Determinent of given matrix is = ";
    
            x = a[0] * (a[4] * a[8] -a [5] * a[7]);
            y = a[1] * (a[3] * a[8] -a [5] * a[6]);
            z = a[2] * (a[3] * a[7] -a [4] * a[6]);
            det = x - y + z;
    
            cout << det 
                 << endl
                 << endl
                 << endl
                 << endl;
    
            if (det == 0)
            {
                cout << "As Determinent=0 so it is singular matrix and its inverse cannot exist"
                     << endl
                     << endl;
    
                goto quit;
            }
    
            b[0] = a[4] * a[8] - a[5] * a[7];
            b[1] = a[5] * a[6] - a[3] * a[8];
            b[2] = a[3] * a[7] - a[4] * a[6];
            b[3] = a[2] * a[7] - a[1] * a[8];
            b[4] = a[0] * a[8] - a[2] * a[6];
            b[5] = a[1] * a[6] - a[0] * a[7];
            b[6] = a[1] * a[5] - a[2] * a[4];
            b[7] = a[2] * a[3] - a[0] * a[5];
            b[8] = a[0] * a[4] - a[1] * a[3];
    
            cout << "Adjoint of given matrix is"
                 << endl
                 << endl;
    
            for (i = 0; i < 3; i++)
            {
                cout << b[i]
                     << "  "
                     << b[i+3]
                     << "  "
                     << b[i+6]
                     << endl
                     <<endl;
            }
    
            cout << endl
                 <<endl;
    
            cout << "Inverse of given matrix is "
                 << endl
                 << endl
                 << endl;
    
            for (i = 0; i < 3; i++)
            {
                cout << b[i]
                     << "/"
                     << det
                     << "  "
                     << b[i+3]
                     << "/" 
                     << det
                     << "  "
                     << b[i+6]
                     << "/" 
                     << det
                     << endl
                      <<endl;
            }
    
            quit:
    
            cout << endl
                 << endl;
    
            cout << "Do You want to continue this again press (y/yes,n/no)";
    
            cin >> ch; 
    
            cout << endl
                 << endl;
        } /* end do */
    
        while (ch == 'y');
        getch ();
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题