tags:

views:

181

answers:

6

I'm printing debug statements for a 4x4 matrix. Does anyone know of a better way to do this, without using cout?

// num decimal places to show
void print( int decimals )
{
    char fmtString[ 300 ] ;

    // I'm thinking this should be able to get smaller.
    sprintf(fmtString,
            "%%.%df %%.%df %%.%df %%.%df\n"
            "%%.%df %%.%df %%.%df %%.%df\n"
            "%%.%df %%.%df %%.%df %%.%df\n"
            "%%.%df %%.%df %%.%df %%.%df",
            decimals, decimals, decimals, decimals, 
            decimals, decimals, decimals, decimals, 
            decimals, decimals, decimals, decimals, 
            decimals, decimals, decimals, decimals ) ;

    printf(fmtString,
           m[0][0], m[0][1], m[0][2], m[0][3],
           m[1][0], m[1][1], m[1][2], m[1][3],
           m[2][0], m[2][1], m[2][2], m[2][3],
           m[3][0], m[3][1], m[3][2], m[3][3] ) ;
}

Super bonus points for preprocessor!

+1  A: 

How 'bout a way to do it that's not tied to the matrix size? You have to rewrite the entire method for a 5x5, 6x6...nxn matrix. A better way? Why not nested looping over all rows and columns? I definitely would not use the C-style printing, because I don't want to deal with creating the formating string. Just use the cout stream.

I'd also recommend that you either pass in the matrix to be printed, to keep things generic, or make this a method on your Matrix class so it operates on its data members. You do have a matrix class, don't you? If I recall correctly, C++ is an object-oriented language.

duffymo
C++ is a multiparadigm language. It supports OOP constructs.
EFraim
Yes, I know. My point is that if you're writing something that could benefit from objects and abstraction, like a matrix, why would you not want to use them?
duffymo
+2  A: 

This is a simple way, just replace cout with printf! Although I like C++ streams more because they are more elegant IMO:

#include <iostream>
#include <iomanip>

template <std::size_t rows, std::size_t columns>
void printMatrix(double (&matrix)[rows][columns], int dec)
{
    std::cout << std::fixed << std::setprecision(dec);
    for(std::size_t r = 0; r < rows; r++)
    {
     for(std::size_t c = 0; c < columns; c++)
     {
      std::cout << matrix[r][c] << '\t';
     }
     std::cout << '\n';
    }
}

int main()
{
    double matrix[4][4];

    printMatrix(matrix, 2);
}
AraK
How will std::setprecision work if you replace cout with printf?
Pete Kirkham
He has to find a way, I don't not know/use printf style functions :)
AraK
+3  A: 

How about:

void print( int decimals = 2 )
{
    int dimension = 4;
    for(int i = 0; i < dimension; i++) {
        for(int j = 0; j < dimension; j++) {
            printf("%.*f", decimals, matrix[i][j]);
            if(j == dimension - 1) printf("\n");
            else                   printf(" ");
        }
    }
}
sepp2k
pfff.... If you're going down that road you should do not stop there, do printf("%.*f%c", decimals, matrix[i][j],(j==3)?'\n':' ');:-)
fvu
Why if(j == 3)?! if(j == dimension-1) !
EFraim
Excellent point EFraim
fvu
@EFraim: You're right, of course. Fixed. @fvu: Going down what road?
sepp2k
@sepp2k the road of traditional C code.
fvu
+1  A: 

In C, with no default arguments. I also don't like the global variable, so I made m a parameter.

#include <stdio.h>
void print(double *m, int decs) {
  int k;
  for (k=0; k<16; k++) {
    printf("%.*f", decs, *m++);
    if (k%4 == 3) puts("");
    else putchar(' ');
  }
}

int main(void) {
  double m[4][4] = {{1/5,1/6,1/9,-1/4}, {0,1/4,-1/7,1/16},
                    {1/2,-1/2,1/3,-1/3}, {1/1,1/2,1/3,1/4}};
  print(&m[0][0], 2);
  return 0;
}


Edit: size passed in parameters

#include <stdio.h>
void print(double *m, int cols, int rows, int decs) {
  int k, s = cols*rows;
  for (k = 0; k < s; k++) {
    printf("%.*f", decs, *m++);
    if ((k + 1) % cols) putchar(' ');
    else                puts("");
  }
}

int main(void) {
  double m[4][4] = {{1/5,1/6,1/9,-1/4}, {0,1/4,-1/7,1/16},
                    {1/2,-1/2,1/3,-1/3}, {1/1,1/2,1/3,1/4}};
  print(&m[0][0], 4, 4, 2);
  return 0;
}
pmg
+3  A: 

Super bonus points for a preprocessor based solution the (wo)man said. Here we go, with big thanks to all people who helped me to get to this.

#include <stdlib.h>
#include <stdio.h>

#define MADU(matrix,decimals,dimension) ({ \
    for(int i = 0; i < dimension; i++) { \
        for(int j = 0; j < dimension; j++) { \
            printf("%.*f%c", decimals, matrix[i][j],(j==dimension-1)?'\n':' '); \
        } \
    } \
})

/*
 * 
 */
int main(int argc, char** argv) {
    double a[4][4];

    MADU(a,2,4);

    return (EXIT_SUCCESS);
}

Please note that this does not really reflect what I would call a good solution.

fvu
uh, wow! I meant.. using a type of token paste - ! :)
bobobobo
+1  A: 

Preprocessor ? This actually sounds like a challenge. Wonder if Boost.Preprocessor is compatible with C but I don't see any reason why it should not. Warning, I won't bother with the includes or the 'wrap-line' marks ;)

 // The formatting of sprintf
 #define PRINT_FORMAT_ELEM(z,n,data) // data is the nbColumns (or -1)
   BOOST_PP_EXPR_IF(
     BOOST_PP_EQUAL(
       BOOST_PP_ADD(n, 1),
       data
     ),
     "%%.%%df\n",
     "%%.%%df "
   )

 #define PRINT_FORMAT_LINE(z,n,data) // data is (nbRows, nbColumns)
   BOOST_PP_REPEAT(
     data,
     PRINT_FORMAT_ELEM,
     BOOST_PP_EXPR_IF(
       BOOST_PP_EQUAL(
         BOOST_PP_ADD(n, 1),
         BOOST_PP_TUPLE_ELEM(2,0,data)
       ),
       -1, // no \n on the last line
       BOOST_PP_TUPLE_ELEM(2,1,data)
     )
   )


 #define PRINT_FORMAT(nbRows, nbColumns)
   BOOST_PP_REPEAT(
     nbRows,
     PRINT_FORMAT_LINE,
     (nbRows, nbColumns)
   )


 // The decimals
 #define PRINT_MATRIX_ELEM(z,n,data) // data is (decimals, notLastRow, nbColumns)
   BOOST_PP_ELEM(3, 0, data)
   BOOST_PP_COMMA_IF(
     BOOST_PP_AND(
       BOOST_PP_TUPLE_ELEM(3, 1, data),
       BOOST_PP_NOT_EQUAL(
         BOOST_PP_ADD(n,1),
         BOOST_PP_TUPLE_ELEM(3, 2, data)
       )
     )
   )

 #define PRINT_DECIMAL_LINE(z, n, data) // data is (decimals, nbRows, nbColumns)
   BOOST_PP_REPEAT(
     BOOST_PP_TUPLE_ELEM(3, 2, data),
     PRINT_MATRIX_ELEM,
     (
       BOOST_PP_TUPLE_ELEM(3, 0, data),
       BOOST_PP_NOT_EQUAL(
         BOOST_PP_ADD(n,1),
         BOOST_PP_TUPLE_ELEM(3, 1, data)
       ),
       BOOST_PP_TUPLE_ELEM(3, 2, data)
     )
   )

 #define PRINT_DECIMALS(decimals, nbRows, nbColumns)
   BOOST_PP_REPEAT(
     nbRows,
     PRINT_DECIMAL_LINE,
     (decimals, nbRows, nbColumns)
   )


 // The matrix itself
 #define PRINT_MATRIX_LINE(z, n, data) // data is (name, nbRows, nbColumns)
   BOOST_PP_REPEAT(
     BOOST_PP_TUPLE_ELEM(3, 2, data),
     PRINT_MATRIX_ELEM,
     (
       BOOST_PP_TUPLE_ELEM(3, 0, data)[n],
       BOOST_PP_NOT_EQUAL(
         BOOST_PP_ADD(n,1),
         BOOST_PP_TUPLE_ELEM(3, 1, data)
       ),
       BOOST_PP_TUPLE_ELEM(3, 2, data)
     )
   )

 #define PRINT_MATRIX_IMPL(name, nbRows, nbColumns)
    BOOST_PP_REPEAT(
      nbRows,
      PRINT_MATRIX_LINE,
      (name, nbRows, nbColumns)
    )


 // And the whole thing
 #define PRINT_MATRIX(string, decimals, name, nbRows, nbColumns)
   sprintf(string,
     PRINT_FORMAT(nbRows, nbColumns),
     PRINT_DECIMALS(decimals, nbRows, nbColumns)
   );

   printf(string,
          PRINT_MATRIX_IMPL(name, nbRows, nbColumns)
   )


 // And now your code:
 void print(int decimals)
 {
   char fmtString[300];

   PRINT_MATRIX(fmtString, decimals, m, 4, 4);
 }

Anyone helps with the code review ;) ?

Matthieu M.
I... I want to cry
EFraim