How to print a beautiful matrix?

How can I print a beautiful matrix with c++?

In the moment I'm uesing this code:

1
2
3
4
5
6
7
8
9
10
11
void print_matrix(double M[nmax][nmax],int n, int m){
	for (int i=0;i<n;i++){
		cout << endl;
		cout << "|";
		for (int k=0;k<m;k++){
			if(k>0) cout << " ";
			cout << M[i][k];
			if(k==m-1) cout << "|";
		}
	}
}

With that code the resualt look like this:
1
2
3
4
|2 1 2 1 6|
|6 -6 6 12 36|
|4 3 3 -3 -1|
|2 2 -1 1 10|


Would like it to look something more like this:
1
2
3
4
|2  1  2  1  6|
|6 -6  6 12 36|
|4  3  3 -3 -1|
|2  2 -1  1 10|

Where the numbers with multi digits ruins the colums, so the colums are not intact. How can I improve the code so the colums are intact?
Last edited on
Please use [code] and [/code] tags for code, and [output] and [/output] format tags to show how you want the matrix to look.
I have now added how I'd like the matrix to be printed.
Column 5 of your desired matrix is separated by a minimum of 2 spaces, but every other column is separated by a minimum of 1 space. Is that intentional?
Last edited on
No, I didn't even see that.. I've changed it now
Last edited on
The easy way to approximate this is to just give a maximum width, using <iomanip> and setw for each cell, however this doesn't scale if you have large numbers like 10000, and can leave excess space if, for example, none of the numbers are negative.

This also doesn't take into account doubles, but the type of your array is of type double, so I'm going to change it to int, and we can adjust it for doubles later.

It's relatively tricky compared to just printing the array in a dumb way because despite printing each row one at a time, you have to look at each column beforehand to see how to align the numbers.

There might be a better way, but: What you need to do is iterate down the first column, find the maximum width of that column, and then then either remember that width or re-calculate it each row. Then, you do the second item in the column, rinse and repeat for each column, then do it all over again for the second row. You could also save the width that each column needs, which requires an extra array, but would reduce redundant calculations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <string>
#include <vector>
using std::cout;

int numlen(int n)
{
    // count number of characters needed for number, +1 if negative
    int length = 0;
    if (n == 0)
        return 1;
    
    if (n < 0)
    {
        n = -n;
        length++;
    }
    
    while (n > 0)
    {
        length++;
        n = n / 10;
    }
    
    return length;
}

const int nmax = 100;

void fancy_print(int M[nmax][nmax], int n, int m){
    
    int max_len_per_column[nmax] {};
    
    for (int col = 0; col < m; col++)
    {
        // determine max length needed for individual column
        int max_len = -1;
        for (int row = 0; row < n; row++)
        {
            int num_length = numlen(M[row][col]);
            if (num_length > max_len)
            {
                max_len = num_length;
            }
        }
        
        max_len_per_column[col] = max_len;
    }
    
    for (int col = 0; col < m; col++)
    {
        std::cout << "Column " << (col + 1) << " needs " << max_len_per_column[col] << " width\n";
    }

    // TODO
}


int main()
{
    #if 0
    std::cout << numlen(-1) << '\n';
    std::cout << numlen(0) << '\n';
    std::cout << numlen(1) << '\n';
    std::cout << numlen(2) << '\n';
    std::cout << numlen(9) << '\n';
    std::cout << numlen(10) << '\n';
    std::cout << numlen(11) << '\n';
    std::cout << numlen(20) << '\n';
    std::cout << numlen(21) << '\n';
    std::cout << numlen(-11) << '\n';
    std::cout << numlen(-20) << '\n';
    #endif
    
    int mat[nmax][nmax] = {
        { 2, 1, 2, 1, 6 },
        { 6, -6, 6, 12, 36 },
        { 4, 3, 3, -3, -1 },
        { 2, 2, -1, 1, 10}
    };
    
    fancy_print(mat, 4, 5);
}

Column 1 needs 1 width
Column 2 needs 2 width
Column 3 needs 2 width
Column 4 needs 2 width
Column 5 needs 2 width

(Note: Add 1 to each of these numbers for the actual setw amount)

In the "TODO" part of my code, you now have the widths needed for each column. Use setw like jonnin linked above. You also need to right-justify each number, using the std::right stream manipulator. See example at:
https://stackoverflow.com/questions/5201619/right-justifying-output-stream-in-c

If you need to handle doubles like 3.003, you will need to decide how many decimal places you want to show, and keep that constant. Remember that floating-point precision is inherently inexact for most numbers, so you have to choose how you want to represent such a number.
Last edited on
doubles are actually easier: you can direct c++ to print everything in scientific notation of a set width. I guess you can do that to ints too, but it may not be what you wanted?
True, scientific notation could be done, but you might still have issues with e123 vs e42, and still the same issue with negatives. The general solution would be to convert the number to a string and then count the characters to know how much width you need.
Hi, agian never got around to thank you guys..

Thank you Ganado and jonnin, you guys were very helpful! Great that people like you are willing to just sit down and help someone with no demands.

This is the code I've ended up with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void print_matrix(double M[nmax][nmax], int n, int m){
    int max_len_per_column[nmax];

    for (int j = 0; j < m; j++){
        int max_len = 0;
        for (int i=0; i<n; i++){
            int num_length = number_of_digits(M[i][j]);
            if (num_length > max_len){
                max_len = num_length;
            }
        }
        max_len_per_column[j] = max_len;
    }
    for (int i=0;i<n;i++){
		cout << endl << setw(2) << "|" << setw(1);
		for (int j=0;j<m;j++){
			cout << setw(max_len_per_column[j]+1);
			cout << M[i][j];
			if(j==m-1) cout << setw(1)<< " |";
    	}
    }
}


And I used this to count the number of digits (including decimals):

1
2
3
4
5
6
7
8
int number_of_digits(double n) {
	int m;
	ostringstream strs;
		strs << n;
		string str = strs.str();
	m = str.size();
	return m;
}


I used the packed sstream, which includes: ostringstream (packed: #include <sstream>)
Don't know really how ostringstream works, found the code on Google somewehere, when trying to find a way to count digits
Last edited on
Somewhat simplified:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <iomanip>
#include <sstream>

constexpr size_t nmax {100};

size_t number_of_digits(double n) {
	std::ostringstream strs;

	strs << n;
	return strs.str().size();
}

void print_matrix(const double M[nmax][nmax], size_t n, size_t m) {
	size_t max_len_per_column[nmax];

	for (size_t j = 0; j < m; ++j) {
		size_t max_len {};

		for (size_t i = 0; i < n; ++i)
			if (const auto num_length {number_of_digits(M[i][j])}; num_length > max_len)
				max_len = num_length;

		max_len_per_column[j] = max_len;
	}

	for (size_t i = 0; i < n; ++i)
		for (size_t j = 0; j < m; ++j)
			std::cout << (j == 0 ? "\n| " : "") << std::setw(max_len_per_column[j]) << M[i][j] << (j == m - 1 ? " |" : " ");

	std::cout << '\n';
}

int main()
{
	const static double mat[nmax][nmax] = {		// On heap, not stack
		{ 2, 1, 2, 1, 6 },
		{ 6, -6, 6, 12, 36 },
		{ 4, 3, 3, -3, -1 },
		{ 2, 2, -1, 1, 10}
	};

	print_matrix(mat, 4, 5);
}



| 2  1  2  1  6 |
| 6 -6  6 12 36 |
| 4  3  3 -3 -1 |
| 2  2 -1  1 10 |

Thanks man
Topic archived. No new replies allowed.