Search code examples
c++formattingprecision

C++ difficulties with stringstream, setw and setprecision


I was trying to format a matrix using stringstream, setw and setprecision. The code looks like this:

template <typename T>
std::string format(std::vector<T> &a, int m, int n, int lda)
{
    std::stringstream ss;
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            ss << std::setw(6);
            ss << a[i + j * lda];
            ss << std::setprecision(2);
        }
        if (i < m - 1)
            ss << std::endl;
    }
    return ss.str();
}

int main()
{
    const int LDA = 5;
    const int N = LDA;

    std::vector<double> a = {
        6.39, 0.00, 0.00, 0.00, 0.00,
        0.13, 8.37, 0.00, 0.00, 0.00,
        -8.23, -4.46, -9.58, 0.00, 0.00,
        5.71, -6.10, -9.25, 3.72, 0.00,
        -3.18, 7.21, -7.42, 8.54, 2.51};

    std::cout << format(a, N, N, LDA) << std::endl;

    return 0;
}

The output looks like this:

  6.39  0.13  -8.2   5.7  -3.2
     0   8.4  -4.5  -6.1   7.2
     0     0  -9.6  -9.2  -7.4
     0     0     0   3.7   8.5
     0     0     0     0   2.5
  1. Why are values like -8.2, 8.4 rounded?
  2. Why aren't zeros formatted?

I was expecting an output like this:

   6.39   0.13  -8.23   5.71  -3.18
   0.00   8.37  -4.46  -6.10   7.21
   0.00   0.00  -9.58  -9.25  -7.42
   0.00   0.00   0.00   3.72   8.54
   0.00   0.00   0.00   0.00   2.51

How do I format it correctly?


Solution

  • You need to move std::setprecision(2) to before you start printing, otherwise the first value will have the default precision. This setting is active until you replace it with something else, so you only need to do it once.

    You also need to set the stream in std::fixed mode.

    Example:

    template <typename T>
    std::string format(std::vector<T> &a, int m, int n, int lda) {
        std::stringstream ss;
        
        ss << std::fixed << std::setprecision(2);    // <- here
    
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                ss << std::setw(6) << a[i + j * lda];
            }
            if (i < m - 1) ss << '\n'; // std::endl; is pointless
        }
        return ss.str();
    }
    

    Demo